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

  1. Pass componentProps as a real object from the caller rather than a string when possible.
  2. If a string is required, ensure it is strict JSON (double quotes, no trailing commas).
  3. Validate/repair the JSON before calling normalizeComponentProps (e.g. JSON5 parse as a softer fallback).
  4. 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

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

Related errors


AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12). Data as JSON: /api/errors/9ce7e2b8bc6c40d1. Report an issue: GitHub.