XACT_S_ALLNORETAIN (0x0004D007) — Transaction Aborted Cleanly
You see this in MSDTC logs when a distributed transaction is aborted without retaining durable resources. The fix is straightforward — here's what to check.
You're staring at MSDTC logs or a transaction coordinator trace, and the error code 0x0004D007 keeps appearing. It's frustrating because the message says "transaction successfully aborted," but something's still wrong — your app hung, a stored procedure timed out, or a COM+ component failed midway. Let's cut through the noise.
The Fix
The root cause is almost always a resource manager (like SQL Server or a transactional file system) that doesn't set the retain flag when the transaction aborts. The MSDTC propagates the abort, but the RM says, "I'm done, nothing to hold onto." The error itself is informational — it's not the problem, it's the symptom.
Here's what to check in order of likelihood:
- Check your MSDTC security configuration. On the machine running the transaction coordinator, open
dcomcnfg→ Component Services → My Computer → Distributed Transaction Coordinator → Local DTC → Properties → Security. Ensure "Network DTC Access" is enabled, and check "Allow Remote Clients" and "Allow Inbound/Outbound" as needed. If you're on Windows Server 2016 or later, also tick "Enable XA Transactions" if you're using XA-compliant resources. Reboot the MSDTC service after changes. - Review the transaction timeout. The default MSDTC timeout is 60 seconds. If your operation takes longer — say a bulk insert or a long-running stored procedure — the coordinator aborts the transaction, and this error appears. Set a higher timeout via registry:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSDTC\Timeout— DWORD value in seconds, up to 3600. Or configure it in your application code:TransactionManager.DefaultTimeout = TimeSpan.FromMinutes(10)in .NET. - Inspect the resource manager. SQL Server is the most common culprit. Run
DBCC OPENTRANto see if there's an orphaned transaction. Also checksys.dm_tran_active_transactionsfor any transactions withdtc_state > 0. If you find one, kill it withKILL session_id. For Oracle, checkV$TRANSACTIONfor pending distributed transactions.
90% of the time, step 1 or 2 resolves it. But you'll still see the error in logs because it's a normal event. The real fix is ensuring your app handles the abort gracefully — catch TransactionAbortedException and retry or log.
Why This Error Occurs
What's actually happening here is a mismatch between how the transaction coordinator and the resource manager communicate. MSDTC uses the OLE Transactions protocol, which defines two abort modes: ABORT_WITH_RETAIN and ABORT_NO_RETAIN. The XACT_S_ALLNORETAIN status means "all resource managers voted to not retain their state after the abort."
The retain flag matters because some RMs (like a transactional file system) need to hold locks after an abort to prevent inconsistency — think of a file that was partially written. But a database like SQL Server typically releases locks on abort. So when all RMs return NO_RETAIN, the coordinator logs this as a success, but your code might not expect the transaction to end.
The reason step 3 works is that orphaned distributed transactions sometimes linger with a PREPARED state. When the coordinator tries to commit after a timeout, it forces an abort, and the RM responds with no retain. Killing the orphan forces a clean state.
Less Common Variations
These are rarer but worth knowing:
- COM+ component with
TransactionRequiredattribute. If a COM+ method runs outside a transaction context, it may throwXACT_E_ABORTEDinternally, and you'll see this error in the Application event log. The fix is to ensure the caller starts a transaction before invoking the component. - Linked server queries in SQL Server. A distributed query across linked servers (e.g., SQL to Oracle) can trigger this if the remote server's MSDTC is misconfigured. Run
SELECT * FROM OPENQUERY(LinkedServerName, 'select 1')to test connectivity. If it hangs, you've found the culprit. - WCF services with
TransactionFlowenabled. If a service operation expects a flowing transaction but the client doesn't include it, the service will abort with this code. Enable transaction flow in both client and server bindings (e.g.,wsHttpBindingwithtransactionFlow="true"). - Third-party XA drivers. Oracle's ODP.NET or IBM's DB2 drivers sometimes have a bug where they don't set the retain flag correctly during recovery. Updating to the latest driver version fixes it. Check
V$XARESOURCEfor stalled XA transactions.
Prevention
You can't prevent this error entirely — it's a normal part of distributed transaction lifecycle logging. But you can stop it from causing you headaches:
- Set explicit transaction timeouts in your application code. Don't rely on defaults. Use
TransactionScopewith aTimeSpanparameter in .NET, orBEGIN DISTRIBUTED TRANSACTIONwithLOCK TIMEOUTin SQL Server. - Monitor MSDTC logs with a tool like
dtcpingorPerfMoncounter "MSDTC Transactions/Aborted". A sudden spike means something upstream is failing. - Design for idempotency — your operations should be safe to retry. If a transaction aborts, the next attempt should not corrupt data. Use savepoints or check preconditions before the real work.
- Avoid mixing
TransactionScopewith ADO.NET connections that haveEnlist=false. This confuses the coordinator. Always let the ambient transaction manage enlistment.
One last thing: if you're using System.Transactions in .NET and you see this error repeatedly, check your TransactionManager.DefaultTimeout setting. I've seen teams set it to 10 minutes but forget to adjust the MSDTC registry timeout — the coordinator wins the race and aborts first. Sync both values.
Was this solution helpful?