abi/screenshot-to-code · warning · HTTPException

Invalid {side} JSON: {error.msg} (line {error.lineno}, colum

Error message

Invalid {side} JSON: {error.msg} (line {error.lineno}, column {error.colno})

What it means

400 raised by _load_openai_input_compare_payload in backend/routes/evals.py:181 when json.loads fails on the left_json or right_json body field of POST /openai-input-compare. The detail includes the exact JSONDecodeError message with line and column, so the syntax error location is identified precisely.

Source

Thrown at backend/routes/evals.py:181

    left_summary: str
    right_summary: str
    left_value: object | None
    right_value: object | None


class OpenAIInputCompareResponse(BaseModel):
    common_prefix_items: int
    left_item_count: int
    right_item_count: int
    difference: OpenAIInputCompareDifferenceResponse | None
    formatted: str


def _load_openai_input_compare_payload(raw_json: str, side: str) -> object:
    try:
        payload = json.loads(raw_json)
    except json.JSONDecodeError as error:
        raise HTTPException(
            status_code=400,
            detail=(
                f"Invalid {side} JSON: {error.msg} "
                f"(line {error.lineno}, column {error.colno})"
            ),
        )

    try:
        compare_openai_inputs(payload, payload)
    except ValueError as error:
        raise HTTPException(status_code=400, detail=f"Invalid {side} payload: {error}")

    return payload


@router.post("/openai-input-compare", response_model=OpenAIInputCompareResponse)
async def compare_openai_inputs_for_evals(
    request: OpenAIInputCompareRequest,

View on GitHub (pinned to d026163f58)

Solutions

  1. Use the reported line/column from the detail to fix the syntax error.
  2. Validate both strings with JSON.parse in the client before sending.
  3. Re-export the original payload from the log file unmodified instead of hand-editing.

Example fix

// before
body: JSON.stringify({ left_json: leftTextarea.value, right_json: rightTextarea.value })

// after
const left = JSON.parse(leftTextarea.value); // throws early with position info
const right = JSON.parse(rightTextarea.value);
body: JSON.stringify({ left_json: leftTextarea.value, right_json: rightTextarea.value })
Defensive patterns

Strategy: validation

Validate before calling

function assertJson(text: string, label: string) {
  try { JSON.parse(text); } catch (e) {
    throw new Error(`Invalid ${label} JSON: ${(e as Error).message}`);
  }
}
assertJson(leftJson, 'left');
assertJson(rightJson, 'right');

Try / catch

const res = await fetch('/openai-input-compare', ...);
if (res.status === 400) { /* detail has line/column; jump editor to it */ }

Prevention

When it happens

Trigger: POST /openai-input-compare with a body where left_json or right_json is not valid JSON — trailing commas, unescaped quotes, single-quoted strings, truncated payloads from copy-paste of captured LLM request bodies.

Common situations: Diffing logged OpenAI request payloads that were truncated by log rotation or manually edited; pasting JSON wrapped in smart quotes from a rich-text source.

Related errors


AI-assisted analysis of abi/screenshot-to-code@d026163f58 (2026-08-14). Data as JSON: /api/errors/84a66a5be69c2c47. Report an issue: GitHub.