Skip to content
Astera Technology

Why does the migration ledger say V2 when the data update failed?

Commit the version marker and its actual data mutation in the same transaction.

Download complete case notes and answer keys ↓

Read the source and its declared rule

The original target quantity 2 must remain positive and non-NULL. MigrationV2 attempts its supplied replacement. Updating the ledger toV2 before BEGIN persists that marker even when a later−1 update fails. Corrected code changes both only inside one transaction and rolls back on error.

Filled synthetic input
RecordInput JSON
Base input{"nextQuantity":-1}
Download editable CSV ↓

Compare the actual paths

Failed corrected update leaves actual quantity 2 and ledgerV1. The bad split state is quantity 2 with ledgerV2, misrepresenting a completed migration.

Misleading and corrected outputs
PathOutput JSON
Misleading path{"error":{"code":275},"version":"V2","records":[{"quantity":2}]}
Corrected path{"error":{"code":275},"version":"V1","records":[{"quantity":2}]}
Download editable CSV ↓
Local Node.js program: 22.23.3 or 24.14.1
import {DatabaseSync} from 'node:sqlite';
import {TextDecoder} from 'node:util';
import {inflateSync} from 'node:zlib';
import {posix} from 'node:path';
import {createHash} from 'node:crypto';
const rows=(db,sql)=>db.prepare(sql).all().map(r=>({...r}));
const failed=(action)=>{try{action();return null;}catch(e){return {code:e.errcode??e.code??e.name};}};

import assert from 'node:assert/strict';
const run=function run(i,corrected=true){
    const db=new DatabaseSync(':memory:');try{db.exec("CREATE TABLE ledger(version TEXT);INSERT INTO ledger VALUES('V1');CREATE TABLE target(quantity INTEGER NOT NULL CHECK(quantity>0));INSERT INTO target VALUES(2);");
      if(!corrected)db.exec("UPDATE ledger SET version='V2';");db.exec('BEGIN;');
      const error=failed(()=>{db.prepare('UPDATE target SET quantity=?').run(i.nextQuantity);if(corrected)db.exec("UPDATE ledger SET version='V2';");db.exec('COMMIT;');});
      if(error)db.exec('ROLLBACK;');return {error,version:db.prepare('SELECT version FROM ledger').get().version,records:rows(db,'SELECT * FROM target')};
    }finally{db.close();}
  };
const cases=[{"label":"misleading base","input":{"nextQuantity":-1},"expected":{"error":{"code":275},"version":"V2","records":[{"quantity":2}]},"corrected":false},{"label":"corrected base","input":{"nextQuantity":-1},"expected":{"error":{"code":275},"version":"V1","records":[{"quantity":2}]},"corrected":true},{"label":"successful data and ledger commit","input":{"nextQuantity":4},"expected":{"error":null,"version":"V2","records":[{"quantity":4}]},"corrected":true},{"label":"required target value missing","input":{"nextQuantity":null},"expected":{"error":{"code":1299},"version":"V1","records":[{"quantity":2}]},"corrected":true}];
for(const test of cases){
  const actual=run(test.input,test.corrected);
  assert.deepEqual(actual,test.expected,test.label);
  console.log(test.label,actual);
}
Download runnable example ↓

Check boundaries before the next load

Valid replacement 4 commits withV2. Missing replacementnull fails 1299 and retainsV1/2.

Editable boundary records and expected outputs
CaseInput JSONExpected output JSON
Data and version both commit{"nextQuantity":4}{"error":null,"version":"V2","records":[{"quantity":4}]}
Missing required replacement{"nextQuantity":null}{"error":{"code":1299},"version":"V1","records":[{"quantity":2}]}
Download editable CSV ↓

After the−1 failure, which version marker is truthful?

Show the worked answer

V1. NoV2 data effect committed. Keep V1 and quantity 2 together until a successful migration transaction.

Related resources