zylon-ai/private-gpt · error · MalformedJSON
Failed to parse JSON: {e!s}
Error message
Failed to parse JSON: {e!s} What it means
Raised inside partial_json_loads when the underlying partial_json_parser.loads call fails with an exception that is neither MalformedJSON nor a JSONDecodeError — the generic branch wraps it in MalformedJSON('Failed to parse JSON: ...') with the original exception chained. Note the deliberate design: partial JSON is tolerated (that is the function's purpose), 'Extra data' payloads are recovered via JSONDecoder.raw_decode, and only truly unexpected failures (wrong input type, non-string, internal errors) hit this wrapper. The {e!s} placeholder is interpolated with the original exception's message.
Source
Thrown at private_gpt/components/llm/utils.py:132
if add_generation_prompt:
parts.append("<|im_start|>assistant\n")
return "\n".join(parts)
# partial_json_parser doesn't support extra data and
# JSONDecorder.raw_decode doesn't support partial JSON
def partial_json_loads(input_str: str, flags: Allow) -> tuple[Any, int]:
try:
return (partial_json_parser.loads(input_str, flags), len(input_str))
except (MalformedJSON, JSONDecodeError, json.JSONDecodeError) as e:
message = getattr(e, "msg", None)
if isinstance(message, str) and "Extra data" in message:
dec = JSONDecoder()
return dec.raw_decode(input_str)
raise
except Exception as e:
raise MalformedJSON(f"Failed to parse JSON: {e!s}") from e
View on GitHub (pinned to 4a030776a3)
Solutions
- Ensure input_str is a str (decode bytes, guard None) before calling partial_json_loads.
- Inspect the chained cause (`except MalformedJSON as e: e.__cause__`) to see the real failure.
- If parsing complete (not partial) JSON, use json.loads directly.
- Pin/upgrade partial_json_parser if the cause indicates a parser bug.
Example fix
# before
obj, idx = partial_json_loads(raw_chunk, flags) # raw_chunk may be bytes
# after
obj, idx = partial_json_loads(raw_chunk.decode('utf-8') if isinstance(raw_chunk, bytes) else raw_chunk or '', flags) Defensive patterns
Strategy: try-catch
Validate before calling
if not isinstance(fragment, str):
fragment = '' if fragment is None else str(fragment) Type guard
def is_parseable_fragment(s: Any) -> bool:
return isinstance(s, str) Try / catch
try:
obj, consumed = partial_json_loads(fragment, flags)
except MalformedJSON:
obj, consumed = None, 0 # skip this chunk in the streaming accumulator Prevention
- Type-check stream chunks (str) before feeding the accumulator; decode bytes at the source.
- Log e.__cause__ when MalformedJSON escapes to identify the real parser failure.
When it happens
Trigger: Calling partial_json_loads with a non-string input (bytes, None, dict) causing a TypeError inside the parser; parser-internal errors from exotic malformed fragments that are neither decode errors nor 'Extra data'; streaming tool-call/JSON output where the accumulated fragment triggers an unexpected parser exception rather than a normal partial-JSON state.
Common situations: Streaming LLM JSON tool-call accumulation where a chunk yields invalid input types; downstream code passing raw bytes from a socket; version changes in partial_json_parser surfacing new exception types.
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
- Last item is a FlexibleModel, expected a specific output_cls
- Invalid CALL statement format
- zpgt.ingest.parsing_failure.error
- zpgt.ingest.no_valid_nodes.error
- zpgt.ingest.parsing_failure.error
AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15).
Data as JSON: /api/errors/0b08fa4098e887f8.
Report an issue: GitHub.