srbhr/Resume-Matcher · error · ValueError
No JSON found in response: {original[:200]}
Error message
No JSON found in response: {original[:200]} What it means
After stripping think tags, extracting code fences, and locating JSON boundaries, _extract_json raises this ValueError when no JSON structure can be found at all in the model response. It also logs a 200-char preview of the unrecognized format (LLM-007) for debugging.
Source
Thrown at apps/backend/app/llm.py:1181
"JSON extraction found unbalanced braces (depth=%d), possible truncation",
depth,
)
if end_idx != -1:
return content[: end_idx + 1]
# Try to find JSON object in the content (only if not already at start)
start_idx = content.find("{")
if start_idx > 0:
# Only recurse if { is found after position 0 to avoid infinite recursion
return _extract_json(content[start_idx:], _depth + 1)
# LLM-007: Log unrecognized format for debugging
logging.error(
"Could not extract JSON from response format. Content preview: %s",
content[:200] if content else "<empty>",
)
raise ValueError(f"No JSON found in response: {original[:200]}")
async def complete_json(
prompt: str,
system_prompt: str | None = None,
config: LLMConfig | None = None,
max_tokens: int = 4096,
retries: int = 2,
schema_type: str = "resume",
) -> dict[str, Any]:
"""Make a completion request expecting JSON response.
Uses JSON mode when available, with app-level retries for content-quality
issues (malformed JSON, truncation). Transport retries (429, 500, timeout)
are handled by the Router and are NOT retried again here.
Args:
schema_type: Expected schema — "resume", "enrichment", "diff",View on GitHub (pinned to 116f9cc3b0)
Solutions
- Strengthen the prompt: 'Respond with ONLY a valid JSON object. Start with { and end with }.'
- Use a model/provider that supports JSON mode (see _supports_json_mode) so response_format json_object is enforced
- Check the logged 'Could not extract JSON from response format. Content preview:' line to see what the model actually returned
- Retry with a stronger model or lower temperature; complete_json already retries with a corrective suffix
Example fix
// before
const prompt = 'List the skills in this resume.';
// after
const prompt = 'List the skills in this resume. Respond with ONLY a JSON object like {"skills": [...]}. No prose.'; Defensive patterns
Strategy: retry
Validate before calling
import json, re
def looks_like_json(s: str) -> bool:
s = s.strip()
if s.startswith("```"):
s = re.sub(r"^```[a-z]*\n|```$", "", s).strip()
return s.startswith(("{", "[")) and bool(_try_loads(s))
def _try_loads(s):
try: json.loads(s)
except Exception: return None
return True Try / catch
try:
data = await complete_json(prompt)
except ValueError as e:
if e.message.starts with "No JSON found":
# inspect logged content preview, then retry with stricter instruction
data = await complete_json(prompt + "\nOutput ONLY raw JSON. No markdown, no explanation.")
else:
raise Prevention
- End prompts with an explicit JSON-only instruction and a schema example
- Use a JSON-mode-capable model so response_format is enforced
- Check the logged 'Content preview' to diagnose recurring bad formats
- Prefer lower temperature for structured-output requests
When it happens
Trigger: complete_json receives a response containing no parseable JSON object/array — the model answered in plain prose, refused the task, or wrapped output in an unrecognized format the extractor doesn't handle.
Common situations: Weak/small model ignoring 'output JSON only' instructions; model safety-refuses the prompt; prompt ambiguous so the model narrates instead of emitting JSON; non-JSON-mode model where response_format is unsupported.
Related errors
- JSON extraction exceeded max recursion depth: {_depth}
- Content too large for JSON extraction: {len(content)} bytes
- LLM completion failed. Please check your API configuration a
- Empty response from LLM
- Failed to parse JSON after {retries + 1} attempts: {e}
AI-assisted analysis of srbhr/Resume-Matcher@116f9cc3b0 (2026-08-28).
Data as JSON: /api/errors/24762dee554e9925.
Report an issue: GitHub.