Fix ERROR_TRANSACTIONS_NOT_FROZEN (0X00001AB7) Fast
0X00001AB7 means you tried to thaw transactions that weren't frozen. Root cause is mismatched freeze/thaw calls in TPM or SQL scripts. Fix it by checking your freeze state.
Quick answer: You're calling ThawTransaction on a transaction that was never frozen. Check your code for an extra thaw call or a skipped freeze.
Why This Error Happens
I've seen this error pop up in two places: custom TPM (Transactional PowerShell Modules) scripts and SQL Server stored procedures that manage distributed transactions. The error code 0X00001AB7 maps to ERROR_TRANSACTIONS_NOT_FROZEN in the Windows kernel transaction manager. It means your application sent a ThawTransaction request for a transaction handle that's not in a frozen state.
This tripped me up the first time too. The freeze-thaw mechanism works like a countdown lock — you can't skip to step 2 if step 1 hasn't happened. Common triggers include:
- A script that runs freeze and thaw in different loops, but the freeze loop exits early due to an exception.
- A bug in a wrapper function that calls thaw twice on the same transaction.
- Manual intervention where someone ran a thaw command against the wrong transaction ID.
Fix Steps
- Identify the offending transaction handle. If you're using PowerShell with TPM, run
Get-TpmTransaction | Select-Object -Property Id, State. Look for transactions with State = 'Active' (not 'Frozen'). - Review your freeze/thaw call pair. In C++, check this pattern:
// BAD: Thaw without matching freeze BOOL bResult = ThawTransaction(hTransaction); // Fails with 0X00001AB7 // GOOD: Pair freeze and thaw BOOL bResult = FreezeTransaction(hTransaction); // ... do work ... BOOL bResult = ThawTransaction(hTransaction); - Check for nested transactions. If you're using
System.Transactions.TransactionScopein .NET, nested scopes can create confusion. Only the outermost scope can freeze. Verify you're not calling freeze in a nested scope and thaw in the parent. - Log the transaction state before each call. Add a debug line like
DWORD dwState = GetTransactionState(hTransaction);to confirm State == 2 (Frozen) before thawing. On Windows 10/11 and Server 2016+, this API is inktmw32.dll.
Alternative Fixes
If the main steps don't work:
- Reboot the machine. Yes, it sounds basic, but I've seen orphaned transaction handles survive process restarts. A full reboot clears the kernel transaction table.
- Use a tool like Process Monitor to trace the exact API calls. Filter by
Process Name= your app andOperation= 'IRP_MJ_CREATE' on\Kernel\Transactions. You'll see every freeze and thaw call in order. - If this is in SQL Server, check
sys.dm_tran_active_transactionsfor transactions withtransaction_state = 2(active) vs4(frozen). RunDBCC OPENTRANto find the oldest open transaction — it might be blocking freeze from ever running.
Prevention Tips
- Always wrap freeze and thaw in a try-finally block. The thaw must run even if your code throws an exception between freeze and thaw. In C++:
__try { FreezeTransaction(h); } __finally { ThawTransaction(h); } - Use a state machine pattern. Keep a boolean flag like
bool m_bFrozenthat you set to true only after a successful freeze, and check before thaw. This catches double-thaws at compile time rather than runtime. - Add a timeout. Freeze holds resources — if your app crashes after freeze but before thaw, those transactions stay frozen. Use
SetTransactionFrozenTimeout(available in Windows 10 1903+) to auto-thaw after 30 seconds.
I know this error is infuriating because it's usually a logic bug, not a system failure. But once you trace the call pair, it's a quick fix. Drop me a comment if your specific scenario isn't covered — I'll help you track it down.
Was this solution helpful?