Skip to content
Astera Technology

Why did a repeated JSON field lose its first supplied value?

Reject duplicate members before accepting a parsed object that has already lost an occurrence.

Download complete case notes and answer keys ↓

Read the source and its declared rule

The original import requires unique decoded member names within each JSON object. Raw qty 2 then qty 3 parses here as one qty 3, but that is insufficient evidence to choose the intended source quantity. The local scanner first validates JSON syntax, then detects duplicate decoded names inside each object scope.

Filled synthetic input
RecordInput JSON
Base input{"raw":"{\"qty\":2,\"qty\":3}"}
Download editable CSV ↓

Compare the actual paths

Good output holds the raw source and both-name collision evidence. The same member name in two different array objects is not a duplicate within one object.

Misleading and corrected outputs
PathOutput JSON
Misleading path{"accepted":true,"value":{"qty":3}}
Corrected path{"accepted":false,"error":"duplicate-json-members","duplicateNames":["qty"],"raw":"{\"qty\":2,\"qty\":3}"}
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 parsed=JSON.parse(i.raw);if(!corrected)return {accepted:true,value:parsed};
    let at=0;const duplicateNames=[];
    const space=()=>{while(/\s/.test(i.raw[at]??'')&&at<i.raw.length)at++;};
    const string=()=>{const start=at++;while(at<i.raw.length){const c=i.raw[at++];if(c==='\\'){at++;continue;}if(c==='"')break;}return JSON.parse(i.raw.slice(start,at));};
    const value=()=>{space();const token=i.raw[at];if(token==='"'){string();return;}
      if(token==='{'){at++;space();const seen=new Set();if(i.raw[at]==='}'){at++;return;}
        for(;;){space();const key=string();if(seen.has(key))duplicateNames.push(key);seen.add(key);space();at++;value();space();if(i.raw[at++]==='}')return;}}
      if(token==='['){at++;space();if(i.raw[at]===']'){at++;return;}for(;;){value();space();if(i.raw[at++]===']')return;}}
      while(at<i.raw.length&&!/[\s,\]}]/.test(i.raw[at]))at++;
    };value();return duplicateNames.length?{accepted:false,error:'duplicate-json-members',duplicateNames,raw:i.raw}:{accepted:true,value:parsed};
  };
const cases=[{"label":"misleading base","input":{"raw":"{\"qty\":2,\"qty\":3}"},"expected":{"accepted":true,"value":{"qty":3}},"corrected":false},{"label":"corrected base","input":{"raw":"{\"qty\":2,\"qty\":3}"},"expected":{"accepted":false,"error":"duplicate-json-members","duplicateNames":["qty"],"raw":"{\"qty\":2,\"qty\":3}"},"corrected":true},{"label":"same name in separate objects","input":{"raw":"[{\"qty\":2},{\"qty\":3}]"},"expected":{"accepted":true,"value":[{"qty":2},{"qty":3}]},"corrected":true},{"label":"escaped equivalent member name","input":{"raw":"{\"qty\":2,\"q\\u0074y\":3}"},"expected":{"accepted":false,"error":"duplicate-json-members","duplicateNames":["qty"],"raw":"{\"qty\":2,\"q\\u0074y\":3}"},"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

Separate object scopes accept. An escaped spelling decoding to qty still collides with qty.

Editable boundary records and expected outputs
CaseInput JSONExpected output JSON
Name repeated across separate objects{"raw":"[{\"qty\":2},{\"qty\":3}]"}{"accepted":true,"value":[{"qty":2},{"qty":3}]}
Escaped name equals an earlier member{"raw":"{\"qty\":2,\"q\\u0074y\":3}"}{"accepted":false,"error":"duplicate-json-members","duplicateNames":["qty"],"raw":"{\"qty\":2,\"q\\u0074y\":3}"}
Download editable CSV ↓

May qty 3 be accepted simply because the parser retained it?

Show the worked answer

No. The supplied admission rule rejects the repeated member and retains the complete raw JSON for correction.

Related resources