srbhr/Resume-Matcher · error · HTTPException

detail

Error message

detail

What it means

_raise_improve_error is the shared error funnel for the resume-improve endpoints (preview and confirm). It logs the underlying exception server-side with the action and stage, then re-raises a generic HTTPException with status 500 and a client-facing detail string. The 'detail' message is that client-facing string produced when a stage of the improve pipeline (LLM call, diff application, DB write, etc.) fails and the endpoint funnels the failure through this helper.

Source

Thrown at apps/backend/app/routers/resumes.py:200

        return ""
    if isinstance(value, str):
        return unicodedata.normalize("NFC", value).strip()
    if isinstance(value, (int, float, bool)):
        return str(value)
    normalized = _normalize_payload(value)
    return json.dumps(
        normalized, sort_keys=True, separators=(",", ":"), ensure_ascii=False
    )


def _raise_improve_error(
    action: str,
    stage: str,
    error: Exception,
    detail: str,
) -> NoReturn:
    logger.error("Resume %s failed during %s: %s", action, stage, error)
    raise HTTPException(status_code=500, detail=detail)


def _get_original_resume_data(resume: dict[str, Any]) -> dict[str, Any] | None:
    original_data = resume.get("processed_data")
    if not original_data and resume.get("content_type") == "json":
        try:
            original_data = json.loads(resume["content"])
        except json.JSONDecodeError as e:
            logger.warning("Skipping resume diff due to JSON parse failure: %s", e)
    return original_data


def _get_original_markdown(resume: dict[str, Any]) -> str | None:
    """Get the original markdown content from a resume.

    Checks ``original_markdown`` first (persisted at upload), then
    falls back to ``content`` if it's still in markdown format.
    """

View on GitHub (pinned to 116f9cc3b0)

Solutions

  1. Check the backend log line 'Resume ... failed during <stage>: <error>' for the real underlying exception
  2. Verify LLM config: provider, model, and API key are set and the provider is reachable (POST /config/llm-test)
  3. Retry the preview; if it times out near 240s, reduce resume size or use a faster model
  4. Re-upload/reprocess the resume (/{id}/retry-processing) if stored processed_data is corrupt

Example fix

// before: raw provider exception surfaced with no stage context
except Exception as e:
    raise HTTPException(status_code=500, detail=str(e))
// after: logged server-side, generic detail to client
except Exception as e:
    _raise_improve_error("improve", "preview", e, "Resume improvement failed. Please try again.")
Defensive patterns

Strategy: try-catch

Validate before calling

// client: confirm LLM is healthy before an improve run
const st = await fetch('/api/v1/status').then(r => r.json());
if (!st.llm_healthy) throw new Error('LLM not configured; fix config before improving');

Try / catch

try {
  await api.post('/resumes/improve/preview', payload);
} catch (e) {
  if (e.response?.status === 500) {
    console.warn('Improve failed server-side; see backend logs for stage');
    // offer user a retry rather than a hard failure
  }
}

Prevention

When it happens

Trigger: Any exception inside improve_resume_preview_endpoint or improve_resume_confirm_endpoint that is caught and passed to _raise_improve_error: LLM completion failures/timeouts, diff generation or verification errors, database errors, or PDF/parsing steps raising mid-pipeline.

Common situations: LLM provider misconfigured or key missing/expired; local model (Ollama/llama.cpp) down or slow; 240s asyncio.wait_for timeout exceeded on a long preview; SQLite lock or schema mismatch; a malformed resume record causing a downstream service to throw.

Related errors


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