0XC0190059

Fix STATUS_NO_LINK_TRACKING_IN_TRANSACTION (0xC0190059)

This error hits when a distributed link-tracking call runs inside an active transaction. Here's how to fix it.

You ran a file operation inside a transaction — maybe a MoveFileEx in a TxF wrapper, or something the Distributed Link Tracking (DLT) client touched — and NTFS threw back 0xC0190059. The message is literal: the link-tracking operation could not be completed because a transaction is active. NTFS is refusing to do two things at once that it can't reconcile.

What's actually happening here is a layering conflict. The Distributed Link Tracking client lives above the filesystem. It maintains the tracked shell links that let a shortcut survive when you move its target file around. TxF (Transactional NTFS) sits inside the filesystem and wraps operations in a Kernel Transaction Manager transaction so they commit or roll back atomically. When a file op that would normally trigger link tracking runs inside a live KTM transaction, NTFS gets a request it can't satisfy without breaking the transaction's atomicity. It bails with STATUS_NO_LINK_TRACKING_IN_TRANSACTION.

The classic trigger is a backup or deployment script that calls CreateTransactionMoveFileTransactedCommitTransaction on a directory that contains .lnk files or lives under a shell-tracked path like %USERPROFILE%\Documents. Another one: a VSS-based imaging tool doing a transactional restore into a user profile. Both blow up the same way.

Cause 1: Link tracking is enabled on the operation inside the transaction

This is the one you'll hit nine times out of ten. You're running a transactional file operation on a path where NTFS would normally fire the link-tracking callback, and NTFS can't defer that callback until after commit.

The real fix: turn off link tracking for the operation. There's no per-call flag for it, so you set the NTFS volume or file attribute. The most reliable approach is to strip the shortcut-bearing content out of the transaction scope. Move the .lnk files in a separate, non-transactional pass after CommitTransaction returns. That sounds crude, but the link tracking subsystem is idempotent — it'll reconcile after the move completes.

If you can't split the operation, use SetFileInformationByHandle with FileDispositionInfo on the link files first to mark them for deletion outside the transaction, then do the transactional move on the remaining payload. The link-tracking client sees ordinary file deletions and doesn't need to be inside your KTM scope.

For C# callers using System.Transactions with FileStream and DTC enlistment, this pattern shows up when someone wraps a directory move in TransactionScope and the directory has .lnk files:

// Bad — will throw IOException wrapping 0xC0190059
using (var scope = new TransactionScope())
{
    Directory.Move(src, dst); // triggers DLT callback → NTFS rejects
    scope.Complete();
}

Split it. Do the transactional work first, then move the shortcuts after:

using (var scope = new TransactionScope())
{
    MoveNonLinkFiles(src, dst);
    scope.Complete();
}
MoveLinkFiles(src, dst); // outside the transaction

Why does this work? Because the link-tracking callback only fires inside the transactional write path. Once scope.Complete() has committed and the KTM transaction is torn down, the filesystem is back to normal semantics and DLT runs as it always does.

Cause 2: Distributed Link Tracking service touching files mid-transaction

The second most common trigger is the TrkWks service (Distributed Link Tracking Client) running its background sweep while your transaction is open. TrkWks occasionally scans tracked volumes and updates object identifiers on shortcut targets. If your transaction happens to hold a lock on a file TrkWks wants to touch, the service's link-tracking call gets refused with 0xC0190059. You'll see it in the System event log under source TrkWks with event ID 3 or 4.

You can't stop TrkWks permanently — it's a system service and disabling it breaks shortcuts in weird ways. But you can shrink the window. Stop the service before running a long transactional batch and restart it after:

net stop TrkWks
:: run your transactional restore / deployment
net start TrkWks

That's a blunt instrument for production, so on a live system use the registry to move the link-tracking maintenance interval out of your maintenance window instead. Under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TrkWks\Parameters, set MaintenancePeriod (REG_DWORD, seconds, default 3600) to something longer than your longest transaction. Don't set it to 0 — that disables the maintenance scan and you'll accumulate stale IDs.

One more thing on this cause: if you're seeing 0xC0190059 in the TrkWks log but not in your own code, your transaction isn't the problem — TrkWks is. It's hitting a transaction someone else opened. Check for long-running VSS writers or backup jobs on that volume. SQL Server VSS writer is a notorious offender.

Cause 3: Transacted operations on a ReFS or mounted-folder path

ReFS doesn't support TxF. Mounted folders — a volume mounted to a directory rather than a drive letter — confuse the link-tracking path resolution in ways that make NTFS defensive. If you open a transaction on a file inside a mounted folder that's also under link tracking, you'll get 0xC0190059 even though the file itself has no shortcuts involved.

The fix is simple: resolve the mounted folder to its underlying volume path before opening the transaction. Use GetFinalPathNameByHandle with FILE_NAME_NORMALIZED and VOLUME_NAME_GUID, then do the transacted work against the \\?\Volume{guid}\... path. Link tracking doesn't chase GUID paths, so the callback never fires.

HANDLE h = CreateFileW(mountPath, GENERIC_READ,
    FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
    FILE_FLAG_BACKUP_SEMANTICS, NULL);
WCHAR realPath[MAX_PATH];
GetFinalPathNameByHandleW(h, realPath, MAX_PATH,
    FILE_NAME_NORMALIZED | VOLUME_NAME_GUID);
// Now open the transaction against realPath

If you're on ReFS at all, drop TxF entirely. There's no supported workaround. Use a journal file plus compensating operations on failure instead. TxF on ReFS has been deprecated since Windows 10 1709 and never worked properly.

Quick reference

CauseDetectionFix
.lnk files inside transacted move Error surfaces from your own code path; .lnk files present in source or dest Move shortcuts after CommitTransaction, outside the transaction
TrkWks background sweep collision Event log source TrkWks, ID 3 or 4, coincident with your batch net stop TrkWks / net start TrkWks; or raise MaintenancePeriod
Mounted folder or ReFS path Path contains a mount point; volume filesystem is ReFS Resolve to \\?\Volume{guid}\ via GetFinalPathNameByHandle; on ReFS, abandon TxF

One closing note: this error code is a STATUS_* code, not a Win32 code. If you're looking at an HRESULT, it'll be 0x80190059. Don't grep for the Win32 equivalent — there isn't one. The NTSTATUS translation table maps it to ERROR_TRANSACTIONAL_CONFLICT in some paths, which sends people down the wrong hole. Trust the STATUS code and look at what transaction was open when the call failed.

Related Errors in Database Errors
0X00000992 Fix NERR_BadUasConfig (0X00000992) – User Accounts Database 1040 MySQL ERROR 1040: Too many connections — fix order that works Table 'wp_*' doesn't exist WordPress 'Table Doesn't Exist' After Plugin Install MISCONF Redis is configured to save RDB snapshots, but it is currently not able Redis snapshot write failed: disk full or permission error

Was this solution helpful?

EP
Erropedia Team
Tech Support Editors
The Erropedia editorial team researches and documents real-world tech errors from across Windows, Linux, macOS, networking, databases, cloud platforms, and more. Every solution is reviewed for accuracy and updated as software and systems evolve.