STATUS_FLT_ALREADY_ENLISTED (0XC01C001B) fix
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
- Identify the code that starts the transaction. Look for calls like
TransactionScopein .NET,BEGIN TRANSACTIONin T-SQL, orZwCreateTransactionin Win32. Write down the exact line numbers. - Check if the resource manager is being enlisted more than once. In .NET, search for
Transaction.EnlistVolatileorTransaction.EnlistDurable. In C++, look forZwEnlistTransactionorReuseEnlistment. If you see these inside a loop or a recursive function, that's your problem. - 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 } } - Ensure the transaction scope is disposed properly. If you're using .NET's
TransactionScope, wrap it in ausingblock. Like this:
Don't callusing (var scope = new TransactionScope()) { // do work scope.Complete(); }Disposemanually—let theusingblock handle it. If you don't callComplete(), the transaction rolls back and the enlistment is released. - If using DTC, configure the resource manager to allow single enlistment only. In SQL Server, run:
This forces remote stored procedures to use the same distributed transaction instead of creating a new one.EXEC sp_configure 'remote proc trans', 1; RECONFIGURE; - Restart the application and test with a single user first. Monitor the Windows Application Event Log for
0xC01C001Bafter 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
TransactionScopeconstructor. For SQL Server, setTransaction Timeout=120in the connection string. - Are you using a connection pool? Connection pooling can hold onto transaction enlistments. Clear the pool by running
sp_reset_connectionor addPooling=Falseto 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
fltmccommands. Runfltmc instancesto see loaded filters, thenfltmc 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?