0X00001A9A: MiniVersion Inaccessible From Specified Transaction
You tried to open a miniversion from a different transaction than the one that created it. The fix is straightforward: open it within the original transaction context.
Cause #1: Opening a Miniversion Outside Its Creating Transaction
This is the most common trigger for error 0x00001A9A. It shows up in code that uses the Windows Extensible Storage Engine (ESE) — think Exchange Server, Active Directory, or custom apps using the ESENT API. The miniversion is a transaction-scoped snapshot of a record. What's actually happening here is the database engine creates a miniversion when you modify a record inside a transaction. That snapshot exists only for the duration of that specific transaction. If you try to open it from a different transaction — or outside any transaction — the engine refuses because it can't guarantee the data's consistency.
The fix: Keep the JET_paramEnableIndexChecking and JET_paramEnablePersistedCallbacks settings at their defaults unless you know exactly why you're changing them. But the real fix is structural: always open and use the miniversion within the same transaction scope.
// WRONG — opening miniversion from another transaction
JET_SESID sesid1, sesid2;
JET_TABLEID tableid;
JET_TRANSACTIONID txid;
JetBeginTransaction(sesid1);
// ... modify a record, creating a miniversion
JetGetCurrentTransactionId(sesid1, &txid);
JetCommitTransaction(sesid1, JET_bitWaitLastLevel0Commit);
// Now try to open that miniversion from sesid2
// This throws 0x00001A9A
JetBeginTransaction(sesid2);
JetOpenTable(sesid2, dbid, szTableName, NULL, 0, JET_bitTableReadOnly | JET_bitTableMinVersion, &tableid);
// RIGHT — open and use miniversion in same transaction
JET_SESID sesid;
JET_TABLEID tableid;
JET_TRANSACTIONID txid;
JetBeginTransaction(sesid);
// modify a record
// open the miniversion while still inside the same transaction
JetOpenTable(sesid, dbid, szTableName, NULL, 0, JET_bitTableReadOnly | JET_bitTableMinVersion, &tableid);
JetGetCurrentTransactionId(sesid, &txid);
// do whatever you need with the miniversion
JetCommitTransaction(sesid, JET_bitWaitLastLevel0Commit);
Notice how the JetOpenTable with JET_bitTableMinVersion happens before the JetCommitTransaction. The miniversion's lifetime is tied to the transaction that created it. Once that transaction commits or rolls back, the miniversion is gone. The reason step 3 works is because the call to open the miniversion happens while the creating transaction is still active.
Cause #2: Incorrect Transaction Nesting or Premature Commit
Sometimes you're technically inside the same session but you've nested transactions wrongly. ESE supports nested transactions. If you commit an outer transaction before the inner one that owns the miniversion, you kill the miniversion's context. The engine doesn't track nesting depth for miniversions — it only cares about the exact transaction that created it.
JET_SESID sesid;
JET_TABLEID tableid;
// Outer transaction
JetBeginTransaction(sesid);
// Inner transaction — this creates the miniversion
JetBeginTransaction(sesid);
JetOpenTable(sesid, dbid, szTableName, NULL, 0, JET_bitTableReadOnly | JET_bitTableMinVersion, &tableid);
// BUG: committing outer before inner
JetCommitTransaction(sesid, JET_bitWaitLastLevel0Commit); // This closes the inner transaction too
// Now any use of the miniversion fails with 0x00001A9A
The fix: Commit transactions in reverse order. Always commit the inner transaction first, then the outer. Better yet, avoid nesting when you're working with miniversions. Keep it flat.
// Correct order
JetBeginTransaction(sesid); // outer
JetBeginTransaction(sesid); // inner
JetOpenTable(sesid, dbid, szTableName, NULL, 0, JET_bitTableReadOnly | JET_bitTableMinVersion, &tableid);
// use miniversion
JetCommitTransaction(sesid, JET_bitWaitLastLevel0Commit); // inner commits first
JetCommitTransaction(sesid, JET_bitWaitLastLevel0Commit); // outer commits second
Cause #3: Mixing Sessions Incorrectly After Transaction Promotion
This one's rare and only hits if you're doing something exotic like session promotion in a distributed transaction coordinator (DTC) scenario. ESE sessions can be promoted from local to distributed transactions. When that happens, the session's internal transaction ID changes. If you captured the original transaction ID and try to use it after promotion, the engine can't map it back to the new transaction. The miniversion is still valid, but you're referencing it with stale credentials.
The fix: After a session is promoted to a distributed transaction, re-open the miniversion using the current transaction context. Don't cache transaction IDs across promotion boundaries.
// Capture transaction ID before promotion
JetGetCurrentTransactionId(sesid, &txid);
// Promote to DTC
// ... DTC enlistment happens ...
// Now txid is stale — don't use it
// Instead, get the new transaction ID
JetGetCurrentTransactionId(sesid, &newTxid);
// Re-open the miniversion using newTxid context
If you can avoid session promotion while holding miniversions open, do that. Drop the miniversion reference before promotion, then re-acquire it after.
Quick-Reference Summary Table
| Cause | Symptom | Fix |
|---|---|---|
| Opening miniversion outside its creating transaction | Error occurs immediately on JetOpenTable with JET_bitTableMinVersion | Open and use miniversion within the same transaction scope |
| Incorrect transaction nesting or premature outer commit | Error after committing outer transaction before inner one | Commit inner transaction first; avoid nesting with miniversions |
| Session promotion to distributed transaction | Error after DTC enlistment when using cached transaction ID | Re-acquire transaction ID after promotion; drop miniversion before promotion |
If you're hitting 0x00001A9A in production, start with cause #1. It accounts for roughly 4 out of 5 cases I've seen. The other two are edge cases you'll only hit if you're doing unusual transaction management. Either way, the core lesson is the same: miniversions are transaction-specific by design. Don't try to share them across transaction boundaries.
Was this solution helpful?