srbhr/Resume-Matcher · error · ValueError

Content too large for JSON extraction: {len(content)} bytes

Error message

Content too large for JSON extraction: {len(content)} bytes

What it means

_extract_json enforces MAX_JSON_CONTENT_SIZE as a JSON-010 safety limit; if the LLM response text exceeds it (len(content) > limit), it refuses to parse and raises this ValueError to bound memory/CPU on huge responses.

Source

Thrown at apps/backend/app/llm.py:1111

    stripped = re.sub(r"<think>.*?</think>", "", content, flags=re.DOTALL)
    # Also handle unclosed <think> tag (model may still be "thinking" at end)
    stripped = re.sub(r"<think>.*", "", stripped, flags=re.DOTALL)
    return stripped.strip()


def _extract_json(content: str, _depth: int = 0) -> str:
    """Extract JSON from LLM response, handling various formats.

    LLM-001: Improved to detect and reject likely truncated JSON.
    LLM-007: Improved error messages for debugging.
    JSON-010: Added recursion depth and size limits.
    """
    # JSON-010: Safety limits
    if _depth > MAX_JSON_EXTRACTION_RECURSION:
        raise ValueError(
            f"JSON extraction exceeded max recursion depth: {_depth}")
    if len(content) > MAX_JSON_CONTENT_SIZE:
        raise ValueError(
            f"Content too large for JSON extraction: {len(content)} bytes")

    original = content

    # Strip thinking model tags (deepseek-r1, qwq, etc.)
    if "<think>" in content:
        content = _strip_thinking_tags(content)

    # Remove markdown code blocks
    if "```json" in content:
        content = content.split("```json")[1].split("```")[0]
    elif "```" in content:
        parts = content.split("```")
        if len(parts) >= 2:
            content = parts[1]
            # Remove language identifier if present (e.g., "json\n{...")
            if content.startswith(("json", "JSON")):
                content = content[4:]

View on GitHub (pinned to 116f9cc3b0)

Solutions

  1. Cap output size via max_tokens on the completion request
  2. Prompt the model to produce concise JSON and split very large inputs into smaller requests
  3. Truncate/chunk the resume or job text passed to analyze/generate prompts
  4. If justified, raise MAX_JSON_CONTENT_SIZE in llm.py

Example fix

// before
const response = await router.acompletion({ ...kwargs });
// after
const response = await router.acompletion({ ...kwargs, max_tokens: 4096 });
Defensive patterns

Strategy: validation

Validate before calling

MAX_JSON_CONTENT_SIZE = 1_000_000  # match llm.py

def content_size_ok(s: str) -> bool:
    return len(s.encode('utf-8')) <= MAX_JSON_CONTENT_SIZE

# check the raw response before parsing
assert content_size_ok(response_text), "LLM response exceeds JSON extraction size limit"

Try / catch

try:
    data = await complete_json(prompt)
except ValueError as e:
    if "Content too large" in str(e):
        data = await complete_json(prompt + " Be concise; limit output to essential fields.")
    else:
        raise

Prevention

When it happens

Trigger: complete_json gets a response whose content length exceeds MAX_JSON_CONTENT_SIZE bytes — e.g. the model echoed the whole resume plus verbose enhancements, or generated runaway repetitive output.

Common situations: Very large resumes/jobs fed into analysis prompts with no output size guidance; model loops and produces megabytes of text; missing max_tokens cap on the completion call.

Related errors


AI-assisted analysis of srbhr/Resume-Matcher@116f9cc3b0 (2026-08-28). Data as JSON: /api/errors/9775738e58ea746c. Report an issue: GitHub.