0XC01C001B

STATUS_FLT_ALREADY_ENLISTED (0XC01C001B) fix

Database Errors Intermediate 👁 0 views 📅 Jun 9, 2026

This error hits when a transaction tries to enlist a resource manager that's already enlisted. It's a kernel-level FILTER MANAGER conflict from duplicate transaction calls.

When this error shows up

You'll see STATUS_FLT_ALREADY_ENLISTED (0XC01C001B) when a database application (like SQL Server, Oracle, or a custom app using Microsoft Distributed Transaction Coordinator or Kernel Transaction Manager) tries to enlist a resource manager into a transaction that's already enlisted. This happens most often during high-concurrency workloads—like batch inserts across multiple threads, or when a stored procedure calls a linked server in a loop and the transaction scope isn't properly closed.

I've seen it on Windows Server 2016 and 2019 machines running SQL Server 2017 and 2019. The trigger is usually a piece of code that opens a transaction, calls some APIs (like ZwCreateTransaction or CoCreateTransaction), then tries to enlist the same resource manager again without committing or rolling back the first enlistment. The kernel's filter manager catches this and throws 0xC01C001B.

Root cause in plain English

The Windows Kernel Transaction Manager (KTM) and the Filter Manager (FLTMGR) track every resource manager that's joined to a transaction. Think of it like a guest list at a party—once a resource manager is on the list, it can't be added again until it leaves (commits or rolls back). The error means your code tried to add a guest who's already on the list. It's not a hardware error or a corrupted file—it's a logic bug in your transaction management.

The most common cause: your application opens a transaction, then inside a loop or recursive call, it attempts to enlist the same resource manager again without checking if it's already enlisted. Another common trigger: using DTC (Distributed Transaction Coordinator) with a resource manager that doesn't support multiple enlistments within the same transaction scope.

The fix: step by step

  1. Identify the code that starts the transaction. Look for calls like TransactionScope in .NET, BEGIN TRANSACTION in T-SQL, or ZwCreateTransaction in Win32. Write down the exact line numbers.
  2. Check if the resource manager is being enlisted more than once. In .NET, search for Transaction.EnlistVolatile or Transaction.EnlistDurable. In C++, look for ZwEnlistTransaction or ReuseEnlistment. If you see these inside a loop or a recursive function, that's your problem.
  3. Add a guard to prevent duplicate enlistment. Before calling the enlist function, check a flag or the enlistment handle. For example, in C++:
    HANDLE hEnlistment = NULL;
    if (hEnlistment == NULL) {
        status = ZwEnlistTransaction(hTransaction, hResourceManager, NULL, 0, &hEnlistment);
        if (status != STATUS_SUCCESS) {
            // handle error
        }
    }
  4. Ensure the transaction scope is disposed properly. If you're using .NET's TransactionScope, wrap it in a using block. Like this:
    using (var scope = new TransactionScope()) {
        // do work
        scope.Complete();
    }
    Don't call Dispose manually—let the using block handle it. If you don't call Complete(), the transaction rolls back and the enlistment is released.
  5. If using DTC, configure the resource manager to allow single enlistment only. In SQL Server, run:
    EXEC sp_configure 'remote proc trans', 1;
    RECONFIGURE;
    This forces remote stored procedures to use the same distributed transaction instead of creating a new one.
  6. Restart the application and test with a single user first. Monitor the Windows Application Event Log for 0xC01C001B after each change. If the error goes away with one user, increase concurrency gradually.

What to check if it still fails

If the error persists after the fix, check these three things:

  • Is your transaction timeout too short? If the first enlistment times out and the resource manager tries to re-enlist, you'll get this error. Increase the timeout in your connection string or TransactionScope constructor. For SQL Server, set Transaction Timeout=120 in the connection string.
  • Are you using a connection pool? Connection pooling can hold onto transaction enlistments. Clear the pool by running sp_reset_connection or add Pooling=False to your connection string temporarily to test. If the error stops, you need to manage enlistments properly—either disable pooling or ensure each connection is explicitly enlisted and then de-listed.
  • Is there a third-party driver or filter driver involved? Antivirus software, backup agents, or storage filters can interject their own resource managers. Disable non-Microsoft filter drivers one at a time using fltmc commands. Run fltmc instances to see loaded filters, then fltmc unload [name] for each non-Microsoft filter. If the error stops, contact the vendor for a fix.

Finally, don't mess with the Windows registry for this error—I've seen people try to change KTM timeout values in HKLM\SYSTEM\CurrentControlSet\Services\KtmRm. That won't fix duplicate enlistment logic, and it can destabilize the system. Stick to fixing your code or your connection configuration.

Was this solution helpful?