larksuite/cli · error
trailing data after JSON value
Error message
trailing data after JSON value
What it means
decoderExpectEOF validates that a JSON payload (--sheets/--values) contains exactly one JSON value. After decoding the first value it tries another Decode; if that succeeds, trailing data existed after the value, so this plain error is thrown. It prevents payloads like `{...} garbage` from being silently truncated to the leading object.
Source
Thrown at shortcuts/sheets/lark_sheet_table_io.go:326
return "float64"
case "date":
return "datetime64[ns]"
case "bool":
return "bool"
default:
return "object"
}
}
// decoderExpectEOF ensures the decoder has nothing left to read after a
// successful Decode. json.Decoder accepts trailing non-whitespace after the
// first JSON value (unlike json.Unmarshal), so a payload like `{...} trailing`
// would silently be treated as the leading object only. Use this after the
// first Decode to surface the trailing data as a validation error.
func decoderExpectEOF(dec *json.Decoder) error {
var trailing json.RawMessage
if err := dec.Decode(&trailing); err == nil {
return fmt.Errorf("trailing data after JSON value") //nolint:forbidigo // intermediate error; the caller wraps it into a typed --sheets/--values validation error
} else if !errors.Is(err, io.EOF) {
return fmt.Errorf("trailing data after JSON value: %w", err) //nolint:forbidigo // intermediate error; the caller wraps it into a typed --sheets/--values validation error
}
return nil
}
// tablePutSheetsSkeleton is the one-line --sheets shape inlined on a decode
// error, so the retry needs no --print-schema round trip. Field vocabulary
// mirrors tableSheetIn.
const tablePutSheetsSkeleton = `{"sheets":[{"name":"Sheet1","columns":["City","Revenue"],"dtypes":{"Revenue":"float64"},"data":[["SH",123.4],["BJ",56.7]],"start_cell":"A1"}]}`
// parseTablePutPayload reads --sheets (JSON, supports @file / stdin) into a
// validated payload. UseNumber keeps numeric cells as json.Number so large
// integers (order IDs, etc.) survive without precision loss or scientific
// notation. The wire shape (tableSheetIn: string columns + dtypes/formats maps
// + `data`) is normalized into the internal tableSheetSpec so the rest of the
// file (buildSheetMatrix, sheetCreateDims, …) is unaware of it. Network-free:
// safe from Validate and DryRun.View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Remove everything after the final closing } or ] of the JSON value
- If you need multiple objects, wrap them in one array or one object instead of concatenating
- Re-quote the whole payload so the shell passes it as a single argument
Example fix
// before
--sheets '{"columns":[...]} {"extra":1}'
// after
--sheets '{"columns":[...]}' Defensive patterns
Strategy: validation
Validate before calling
function assertSingleJSONValue(s) {
const v = JSON.parse(s);
const trimmed = s.trim();
// re-serialize round-trip guards against trailing bytes after the value
const probe = trimmed.replace(/^\s*[[{]/, m => m);
JSON.parse(s + '');// syntax check
if (countTopLevel(s) !== 1) throw new Error('trailing data after JSON value');
return v;
}
function countTopLevel(s) { let d=0,n=0,inStr=false,esc=false; for(const c of s){ if(esc){esc=false;continue;} if(c==='\\'){esc=true;continue;} if(c==='"'){inStr=!inStr;continue;} if(inStr)continue; if(c==='{'||c==='[')d++; if(c==='}'||c===']'){d--; if(d===0)n++;}} return n; } Type guard
function isCleanJSONObject(s) { try { JSON.parse(s); return /^\s*[\[{]/.test(s) && /\s*[\]}]\s*$/.test(s); } catch { return false; } } Try / catch
try {
await run(['lark','sheet','table-put','--sheets',payload]);
} catch (e) {
if (/trailing data after JSON value/.test(e.message)) {
payload = JSON.stringify(JSON.parse(payload.trim().replace(/^[\[{]/,'')));
// simplest: rebuild payload via JSON.stringify from the parsed object
}
throw e;
} Prevention
- Build payloads with JSON.stringify instead of hand-concatenating strings
- Never paste JSON together with explanatory text or comments
- Pipe payloads from jq (jq -c .) which guarantees one valid JSON value per output
When it happens
Trigger: Passing a --sheets/--values argument with extra characters after the closing brace/bracket, e.g. '{"columns":[]} extra' or two concatenated JSON objects '{..}{..}', or pasted content with a trailing comment.
Common situations: Pasting JSON from docs with a trailing sentence; concatenating two JSON blobs by mistake; shell appending an unquoted fragment; a stray comma-plus-object tail.
Related errors
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/4bc44eb5725a95b5.
Report an issue: GitHub.