0X00001A9A

0X00001A9A: MiniVersion Inaccessible From Specified Transaction

Database Errors Intermediate 👁 0 views 📅 May 29, 2026

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

CauseSymptomFix
Opening miniversion outside its creating transactionError occurs immediately on JetOpenTable with JET_bitTableMinVersionOpen and use miniversion within the same transaction scope
Incorrect transaction nesting or premature outer commitError after committing outer transaction before inner oneCommit inner transaction first; avoid nesting with miniversions
Session promotion to distributed transactionError after DTC enlistment when using cached transaction IDRe-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?