can1357/oh-my-pi · error · SyntaxError
Expected object key
Error message
Expected object key
What it means
Thrown by RelaxedJson.#key in strict mode when a key position inside an object contains no key characters — the current char is not a quote and not an identifier character. Partial mode returns an empty-string key instead of throwing.
Source
Thrown at packages/utils/src/json-parse.ts:351
}
if (this.#partial) return out;
throw new SyntaxError("Expected ',' or ']' in array");
}
}
#key(): string {
const c = this.#s[this.#i];
if (c === '"' || c === "'") return this.#string(this.#s.charCodeAt(this.#i));
// Unquoted identifier key: read until a structural delimiter / whitespace.
const start = this.#i;
while (this.#i < this.#n) {
const ch = this.#s[this.#i];
if (ch === ":" || ch === "," || ch === "}" || isWhitespace(this.#s.charCodeAt(this.#i))) break;
this.#i++;
}
if (this.#i === start) {
if (this.#partial) return "";
throw new SyntaxError("Expected object key");
}
return this.#s.slice(start, this.#i);
}
#string(quote: number): string {
const s = this.#s;
const n = this.#n;
let i = this.#i + 1; // skip opening quote
let out = "";
let runStart = i;
while (i < n) {
const cc = s.charCodeAt(i);
if (cc !== BACKSLASH && cc !== quote) {
i++;
continue;
}
if (cc === quote) {
// Apostrophe / inner-quote recovery (a quote that isn't followed by aView on GitHub (pinned to 9690622007)
Solutions
- Fix the input so each key is a quoted string or an identifier
- Check whether an interpolated key variable is empty in the code that builds the JSON
- Use parseStreamingJson if the input may be an incomplete streaming prefix
- Validate tool-call arguments against a schema and skip the malformed call rather than executing it
Example fix
// before
const v = parseJsonWithRepair(`{: 1}`); // SyntaxError: Expected object key
// after
const v = parseJsonWithRepair(`{"key": 1}`); // {key: 1} Defensive patterns
Strategy: validation
Validate before calling
// Reject payloads where a punctuation char occupies a key position
const stripped = text.replace(/"(\\.|[^"\\])*"/g, '"S"');
const badKey = /\{\s*[:;,.]/.test(stripped) || /,\s*[:;]/.test(stripped); Try / catch
try {
const value = parseJsonWithRepair<T>(text);
} catch (err) {
if (err instanceof SyntaxError && err.message === "Expected object key") {
// reject the call; check the producing template for an empty/missing key variable
} else throw err;
} Prevention
- Check interpolated key variables are non-empty before building JSON
- Build objects with JSON.stringify from real objects, not string templates
- Schema-validate parsed output; discard malformed tool calls instead of executing them
When it happens
Trigger: parseJsonWithRepair with a stray delimiter where a key should be, e.g. '{: 1}', '{,}', '{"a": 1, :2}', or a punctuation char starting the key slot in strict mode (stray commas alone are already tolerated, so something like ':' or ';' must sit in the key position).
Common situations: Malformed LLM output with a stray colon or punctuation in the key slot; template interpolation producing '{: value}' when the key variable is empty; mangled output from an upstream serializer.
Related errors
- Unexpected trailing characters at position ${this.#i}
- Expected ':' in object
- Expected ',' or '}' in object
- Expected ',' or ']' in array
- Invalid number: ${token}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/e1844da822fec9ff.
Report an issue: GitHub.