{
  "slug": "llm-produced-invalid-json",
  "title": "Repairing malformed JSON from a language model",
  "description": "Models emit JSON wrapped in prose, fenced in markdown, with trailing commas, single quotes, Python literals, or simply cut off. All of it is mechanically fixable.",
  "keywords": [
    "fix llm json",
    "malformed json",
    "json parse error",
    "trailing comma",
    "truncated json",
    "agent json output"
  ],
  "cause": [
    "A model producing JSON is producing tokens that resemble JSON, not serialising a data structure. The failure modes are consistent: markdown fences, an explanatory sentence either side, trailing commas, single or smart quotes, unquoted keys, Python's True/False/None, and truncation when the response hits a length limit.",
    "Asking the model to try again costs another round trip and often reproduces the same fault. The faults are syntactic, so they can be repaired deterministically.",
    "Truncation is the dangerous one: naively trimming to the last closing brace silently discards the final incomplete record, which looks like success."
  ],
  "example": {
    "label": "Repair fenced, single-quoted output with Python literals",
    "curl": "curl -sX POST https://fluentedi.com/v1/json/repair -H 'content-type: application/json' \\\n  -d '{\"input\":\"Here you go!\\n```json\\n{ name: '\"'\"'Ada'\"'\"', active: True, tags: [1,2,], note: None }\\n```\"}'",
    "output": "\"parsed\": {\"name\":\"Ada\",\"active\":true,\"tags\":[1,2],\"note\":null},\n\"changes\": [\n  \"removed a markdown code fence\",\n  \"converted single-quoted strings to double quotes\",\n  \"removed trailing commas\",\n  \"quoted unquoted object keys\",\n  \"converted Python literals (True/False/None) to JSON\"\n]"
  },
  "fix": [
    "Repair first, then decide. The reported changes tell you what your generator got wrong, which is worth more than the repaired output — a recurring fence means your prompt is inviting one.",
    "For truncated output, close the structures rather than trimming to the last brace, so the final partial record survives.",
    "When repair is impossible you get a line, column and caret. Feed that back to the model instead of the whole document."
  ],
  "tools": [
    "https://fluentedi.com/v1/json/repair",
    "https://fluentedi.com/v1/json/query",
    "https://fluentedi.com/v1/json/canonical"
  ]
}