Skip to content
Astera Technology

Why did a migrated child link to an unrelated existing parent?

Translate source references through the actual allocated destination-key map.

Download complete case notes and answer keys ↓

Read the source and its declared rule

The original source parent 7 is imported into a target already containing ids 7 and 100. Its newly allocated destination id is 101. Child source reference 7 means that imported parent, not existing target 7. The fixture stages the imported parent and holds any unmapped child source.

Filled synthetic input
RecordInput JSON
Base input{"existing":[7,100],"sourceId":7,"childSource":7}
Download editable CSV ↓

Compare the actual paths

The wrong child 7 satisfies a basic FK because old target 7 exists, yet points to the wrong record. Correct child 101 follows the actual map source 7→target 101.

Misleading and corrected outputs
PathOutput JSON
Misleading path{"mapping":{"source":7,"target":101},"error":null,"parents":[{"id":7,"label":"Existing"},{"id":100,"label":"Existing"},{"id":101,"label":"Imported"}],"children":[{"parent_id":7}]}
Corrected path{"mapping":{"source":7,"target":101},"error":null,"parents":[{"id":7,"label":"Existing"},{"id":100,"label":"Existing"},{"id":101,"label":"Imported"}],"children":[{"parent_id":101}]}
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('PRAGMA foreign_keys=ON;CREATE TABLE parent(id INTEGER PRIMARY KEY AUTOINCREMENT,label TEXT);CREATE TABLE child(parent_id INTEGER REFERENCES parent(id));');
      for(const id of i.existing)db.prepare('INSERT INTO parent VALUES(?,?)').run(id,'Existing');
      const newId=Number(db.prepare("INSERT INTO parent(label) VALUES('Imported')").run().lastInsertRowid);
      const mapping={source:i.sourceId,target:newId};
      const error=corrected&&i.childSource!==i.sourceId?'unmapped-source-parent':failed(()=>db.prepare('INSERT INTO child VALUES(?)').run(corrected?newId:i.childSource));
      return {mapping,error,parents:rows(db,'SELECT * FROM parent ORDER BY id'),children:rows(db,'SELECT * FROM child')};
    }finally{db.close();}
  };
const cases=[{"label":"misleading base","input":{"existing":[7,100],"sourceId":7,"childSource":7},"expected":{"mapping":{"source":7,"target":101},"error":null,"parents":[{"id":7,"label":"Existing"},{"id":100,"label":"Existing"},{"id":101,"label":"Imported"}],"children":[{"parent_id":7}]},"corrected":false},{"label":"corrected base","input":{"existing":[7,100],"sourceId":7,"childSource":7},"expected":{"mapping":{"source":7,"target":101},"error":null,"parents":[{"id":7,"label":"Existing"},{"id":100,"label":"Existing"},{"id":101,"label":"Imported"}],"children":[{"parent_id":101}]},"corrected":true},{"label":"coincidental source-target number equality","input":{"existing":[],"sourceId":1,"childSource":1},"expected":{"mapping":{"source":1,"target":1},"error":null,"parents":[{"id":1,"label":"Imported"}],"children":[{"parent_id":1}]},"corrected":true},{"label":"unmapped child source","input":{"existing":[7,100],"sourceId":7,"childSource":8},"expected":{"mapping":{"source":7,"target":101},"error":"unmapped-source-parent","parents":[{"id":7,"label":"Existing"},{"id":100,"label":"Existing"},{"id":101,"label":"Imported"}],"children":[]},"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

Coincidental id equality in an empty target does not prove copying keys is safe. Unknown child source 8 is held with no child write.

Editable boundary records and expected outputs
CaseInput JSONExpected output JSON
Coincidental source-target equality{"existing":[],"sourceId":1,"childSource":1}{"mapping":{"source":1,"target":1},"error":null,"parents":[{"id":1,"label":"Imported"}],"children":[{"parent_id":1}]}
Child source has no map{"existing":[7,100],"sourceId":7,"childSource":8}{"mapping":{"source":7,"target":101},"error":"unmapped-source-parent","parents":[{"id":7,"label":"Existing"},{"id":100,"label":"Existing"},{"id":101,"label":"Imported"}],"children":[]}
Download editable CSV ↓

Which destination parent must the base child reference?

Show the worked answer

101, from the recorded allocation map. Target 7 is an unrelated existing record, despite passing FK existence.

Related resources

System integration services →