{"record":{"id":"686720ac7db08515","repo":"run-llama/llama_index","slug":"malformed-partial-json-encountered","errorCode":null,"errorMessage":"Malformed partial JSON encountered.","messagePattern":"Malformed partial JSON encountered\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"llama-index-core/llama_index/core/llms/utils.py","lineNumber":170,"sourceCode":"                char = \"\\\\n\"  # Replace the newline character with the escape sequence.\n            elif char == \"\\\\\":\n                escaped = not escaped\n            else:\n                escaped = False\n        else:\n            if char == '\"':\n                is_inside_string = True\n                escaped = False\n            elif char == \"{\":\n                stack.append(\"}\")\n            elif char == \"[\":\n                stack.append(\"]\")\n            elif char == \"}\" or char == \"]\":\n                if stack and stack[-1] == char:\n                    stack.pop()\n                else:\n                    # Mismatched closing character; the input is malformed.\n                    raise ValueError(\"Malformed partial JSON encountered.\")\n\n        # Append the processed character to the new string.\n        new_s += char\n\n    # If we're still inside a string at the end of processing and no colon was found after the opening quote,\n    # this is an incomplete key - remove it\n    if is_inside_string and '\"' in new_s and \":\" not in new_s[new_s.rindex('\"') :]:\n        new_s = new_s[: new_s.rindex('\"')]\n    elif is_inside_string:\n        new_s += '\"'\n\n    # Check if we have an incomplete key-value pair\n    new_s = new_s.rstrip()\n    if new_s.endswith(\":\"):\n        new_s += \" null\"  # Add a default value for incomplete value\n    elif new_s.endswith(\",\"):\n        new_s = new_s[:-1]  # Remove the trailing comma\n","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/run-llama/llama_index/blob/afd0fef371831f9bda13e5af7167cf4e981278ab/llama-index-core/llama_index/core/llms/utils.py#L152-L188","documentation":"Inside replace_errors/json repair logic used for partial (in-flight) JSON — as streamed structured output arrives, llama-index tracks brackets/quotes and appends missing closers. If a closing '}' or ']' appears that does not match the top of the expected-closer stack (e.g. ']' when a '}' is pending, ignoring matching pairs inside strings), the input cannot be repaired deterministically and ValueError is raised.","triggerScenarios":"Streaming a JSON object where the model emits mismatched brackets mid-stream, or feeding partially accumulated stream text that was cut/concatenated incorrectly (dropped or duplicated chunks) into this repair path.","commonSituations":"Accumulating streamed structured output manually and passing truncated/mangled buffers; models that emit invalid JSON skeletons; chunk handling that reorders or drops tokens.","solutions":["Feed the parser strictly the prefix accumulated so far, in order — never skip or reorder chunks.","Wait for the stream to finish and json.loads the complete text instead of repairing partials.","Catch ValueError per-chunk and skip intermediate unparseable prefixes; retry only on the final buffer.","Use native structured output (function calling / JSON mode) so repair is unnecessary."],"exampleFix":"# before\npartial = chunks[0] + chunks[2]  # dropped chunk -> mismatched brackets\nobj = repair_json(partial)\n# after\npartial = \"\".join(chunks[:i])  # always an in-order prefix\ntry:\n    obj = repair_json(partial)\nexcept ValueError:\n    continue  # skip unparseable intermediate prefix","handlingStrategy":"try-catch","validationCode":"def is_ordered_json_prefix(buffer: str, new_chunk: str) -> bool:\n    # crude guard: only append chunks that continue the current buffer position\n    return isinstance(new_chunk, str) and (buffer == \"\" or True)  # order is caller's job; validate brackets below\n\ndef brackets_balanced_or_open(s: str) -> bool:\n    stack = []\n    in_str = False\n    esc = False\n    for ch in s:\n        if esc:\n            esc = False\n        elif in_str and ch == \"\\\\\":\n            esc = True\n        elif ch == '\"':\n            in_str = not in_str\n        elif not in_str and ch in \"{[\":\n            stack.append(ch)\n        elif not in_str and ch in \"}\":\n            if not stack or stack.pop() != \"{\":\n                return False\n        elif not in_str and ch == \"]\":\n            if not stack or stack.pop() != \"[\":\n                return False\n    return True","typeGuard":"def looks_like_json_stream_prefix(text: str) -> bool:\n    return text.lstrip().startswith((\"{\", \"[\"))","tryCatchPattern":"try:\n    obj = repair_partial_json(buffer)\nexcept ValueError:\n    obj = None  # intermediate prefix unrepairable; wait for more tokens\nif obj is None and stream_finished:\n    raise  # final buffer must parse or the output is genuinely malformed","preventionTips":["Always hand the repair utility a strict in-order prefix of the stream.","Never drop, reorder, or duplicate chunks before parsing.","Treat intermediate ValueError as 'not ready yet', not as a fatal error."],"tags":["llama-index","json","streaming","structured-output","parsing"],"backgroundTag":null,"analyzedSha":"afd0fef371831f9bda13e5af7167cf4e981278ab","analyzedAt":"2026-08-15T05:42:58.429Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}