moeru-ai/airi · error · Error
Invalid JSON for componentProps: ${(error as Error).message}
Error message
Invalid JSON for componentProps: ${(error as Error).message} What it means
Thrown by normalizeComponentProps when raw is a non-empty string that JSON.parse rejects. The componentProps field accepts either a pre-parsed object (passed through) or a JSON string (parsed); a malformed JSON string surfaces the underlying SyntaxError message.
Source
Thrown at apps/stage-tamagotchi/src/renderer/stores/tools/builtin/widgets.ts:216
...input,
windowSize: normalizeWidgetWindowSizeInput(input.windowSize),
}
}
export function normalizeComponentProps(raw?: string | Record<string, any>) {
if (raw === undefined || raw === null)
return {}
if (typeof raw === 'string') {
const payload = raw.trim()
if (!payload)
return {}
try {
const parsed = JSON.parse(payload)
return typeof parsed === 'object' && parsed !== null ? parsed : {}
}
catch (error) {
throw new Error(`Invalid JSON for componentProps: ${(error as Error).message}`)
}
}
if (typeof raw === 'object')
return raw
return {}
}
function resolveWindowSize(
componentName: string | undefined,
componentProps: Record<string, any>,
windowSize?: WidgetWindowSize,
) {
const explicitWindowSize = normalizeWidgetWindowSize(windowSize)
if (explicitWindowSize)
return explicitWindowSize
View on GitHub (pinned to 27111382b4)
Solutions
- Pass componentProps as a real object from the caller rather than a string when possible.
- If a string is required, ensure it is strict JSON (double quotes, no trailing commas).
- Validate/repair the JSON before calling normalizeComponentProps (e.g. JSON5 parse as a softer fallback).
- Show the parse error to the LLM/tool-caller so it can re-emit valid JSON.
Example fix
// before
normalizeComponentProps("{ foo: 'bar', }")
// after
normalizeComponentProps('{ "foo": "bar" }')
// or pass an object directly:
normalizeComponentProps({ foo: 'bar' }) Defensive patterns
Strategy: validation
Validate before calling
function isStrictJsonString(raw: string): boolean {
if (raw.trim().length === 0) return true
try { JSON.parse(raw); return true } catch { return false }
} Type guard
function isParsableComponentProps(raw: unknown): boolean {
if (raw == null) return true
if (typeof raw === 'object') return true
if (typeof raw === 'string') {
if (raw.trim() === '') return true
try { JSON.parse(raw); return true } catch { return false }
}
return false
} Try / catch
try {
normalizeComponentProps(raw)
} catch (e) {
// surface the parse error to the tool-caller / LLM and request valid JSON
} Prevention
- Pass componentProps as an object, not a JSON string, from typed callers.
- Validate the JSON string before the widget tool executes.
- Consider a tolerant parser (JSON5) as a fallback then re-serialize as strict JSON.
When it happens
Trigger: A widget tool call passed componentProps as a string that is not valid JSON — trailing comma, unquoted keys, single quotes, stray characters, or partial JSON. Only the string branch parses; objects pass through untouched.
Common situations: LLM-generated tool call emitted hand-written object-literal text instead of JSON; user typed componentProps manually with JS object syntax; copy-paste introduced smart quotes or a trailing comma.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- prompt is required for image_journal.create
- invalid JSON: ${stringifyError(error)}
- Invalid accelerator: unknown key "${token}"
- Invalid Godot stage scene input payload.
- Gamelet `${bindingId}` is not open.
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/9ce7e2b8bc6c40d1.
Report an issue: GitHub.