Skip to content
Astera Technology

Why does a Chinese field shift the next fixed-width value?

Apply byte-defined field boundaries before decoding each field.

Download complete case notes and answer keys ↓

Read the source and its declared rule

The original format allocates three UTF-8 bytes to name and the remaining two bytes to quantity text. Source bytes encode 你12. The field cut must be a valid character boundary within the supplied byte array; treating three bytes as three JavaScript characters consumes the quantity too.

Filled synthetic input
RecordInput JSON
Base input{"bytes":[228,189,160,49,50],"nameBytes":3}
Download editable CSV ↓

Compare the actual paths

Correct output separates 你 and 12. Strict decoding of each slice also detects a declared cut through the middle of a character.

Misleading and corrected outputs
PathOutput JSON
Misleading path{"accepted":true,"name":"你12","quantityText":""}
Corrected path{"accepted":true,"name":"你","quantityText":"12"}
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 bytes=Uint8Array.from(i.bytes);const decoder=new TextDecoder('utf-8',{fatal:true});
    try{
      if(corrected){return {accepted:true,name:decoder.decode(bytes.slice(0,i.nameBytes)),quantityText:decoder.decode(bytes.slice(i.nameBytes))};}
      const text=decoder.decode(bytes);return {accepted:true,name:text.slice(0,i.nameBytes),quantityText:text.slice(i.nameBytes)};
    }catch{return {accepted:false,error:'field-splits-encoded-character'};}
  };
const cases=[{"label":"misleading base","input":{"bytes":[228,189,160,49,50],"nameBytes":3},"expected":{"accepted":true,"name":"你12","quantityText":""},"corrected":false},{"label":"corrected base","input":{"bytes":[228,189,160,49,50],"nameBytes":3},"expected":{"accepted":true,"name":"你","quantityText":"12"},"corrected":true},{"label":"boundary within character","input":{"bytes":[228,189,160,49,50],"nameBytes":2},"expected":{"accepted":false,"error":"field-splits-encoded-character"},"corrected":true},{"label":"ASCII source boundary","input":{"bytes":[65,66,49,50],"nameBytes":2},"expected":{"accepted":true,"name":"AB","quantityText":"12"},"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

A two-byte cut splits 你 and rejects. Two ASCII name bytes form AB and leave 12 intact.

Editable boundary records and expected outputs
CaseInput JSONExpected output JSON
Cut inside a multibyte character{"bytes":[228,189,160,49,50],"nameBytes":2}{"accepted":false,"error":"field-splits-encoded-character"}
ASCII field boundary{"bytes":[65,66,49,50],"nameBytes":2}{"accepted":true,"name":"AB","quantityText":"12"}
Download editable CSV ↓

Should the name field include 12 in this source?

Show the worked answer

No. Its allocation is three bytes for 你. Quantity text remains the separate two-byte field 12.

Related resources