srbhr/Resume-Matcher · error · ValueError
Failed to parse JSON after {retries + 1} attempts: {e}
Error message
Failed to parse JSON after {retries + 1} attempts: {e} What it means
complete_json attempts to parse the extracted JSON with retries; on the final allowed attempt, if parsing still fails it raises this ValueError including the attempt count and the underlying parse exception. Each retry appends a reminder telling the model to output only a valid JSON object.
Source
Thrown at apps/backend/app/llm.py:1321
except json.JSONDecodeError as e:
# Content quality — malformed JSON, retry with prompt hint
logging.warning(f"JSON parse failed (attempt {attempt + 1}): {e}")
if use_json_mode and not json_mode_failed:
# JSON-012: Registry claimed JSON mode support but the upstream
# failed to return valid JSON. Disable JSON mode for retries.
json_mode_failed = True
logging.warning(
"JSON mode failed for %s, falling back to prompt-only (attempt %d)",
model_name, attempt + 1,
)
if attempt < retries:
messages[-1]["content"] = (
prompt
+ "\n\nIMPORTANT: Output ONLY a valid JSON object. Start with { and end with }."
)
continue
raise ValueError(
f"Failed to parse JSON after {retries + 1} attempts: {e}")
except ValueError as e:
# Content quality — empty response, JSON extraction failure
logging.warning(f"Content extraction failed (attempt {attempt + 1}): {e}")
if attempt < retries:
continue
raise
except litellm.BadRequestError as e:
# JSON-012b: some OpenAI-compatible servers (e.g. LM Studio) report
# response_format support via the registry but reject
# {"type": "json_object"} with a 400 (issue #857). The Router does
# not retry bad requests, so recover here by disabling JSON mode and
# retrying prompt-only. Unrelated 400s (e.g. context length) still
# propagate.
if (
use_json_modeView on GitHub (pinned to 116f9cc3b0)
Solutions
- Increase the retries parameter to give the model more corrective attempts
- Enable JSON mode (response_format json_object) with a model that supports it (see _supports_json_mode)
- Raise max_tokens so output isn't truncated mid-object
- Inspect logs for the parse error 'e' to see exactly which syntax the model keeps producing; simplify the requested schema
Example fix
// before
const data = await complete_json(prompt, { retries: 1 });
// after
const data = await complete_json(prompt, { retries: 3, maxTokens: 4096 }); Defensive patterns
Strategy: retry
Validate before calling
import json
def is_valid_model_json(text: str) -> bool:
try:
json.loads(text)
return True
except json.JSONDecodeError:
return False
# quick pre-check on a sample response before wiring into prod flows Try / catch
try:
data = await complete_json(prompt, retries=3)
except ValueError as e:
if e.message.startswith('Failed to parse JSON after'):
log.error(f"LLM JSON parse exhausted: {e}")
return graceful_degradation_result()
raise Prevention
- Pass retries >= 3 for structured-output calls
- Enable JSON mode (response_format json_object) on supported models
- Raise max_tokens to avoid truncation mid-JSON
- Simplify the requested JSON schema; verify sample outputs in tests
When it happens
Trigger: After retries + 1 LLM calls, json.loads/_extract_json still throws — the model persistently emits near-JSON output (trailing commas, unescaped quotes, comments, truncated output) that never parses.
Common situations: Model generates long JSON that gets truncated by max_tokens; model adds prose or markdown around JSON even after the corrective reminder; JSON mode unsupported for the chosen model.
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
- Failed after {retries + 1} attempts
- LLM completion failed. Please check your API configuration a
- JSON extraction exceeded max recursion depth: {_depth}
- Content too large for JSON extraction: {len(content)} bytes
- No JSON found in response: {original[:200]}
AI-assisted analysis of srbhr/Resume-Matcher@116f9cc3b0 (2026-08-28).
Data as JSON: /api/errors/f9becd1b4dd856b2.
Report an issue: GitHub.