srbhr/Resume-Matcher · error · HTTPException

Invalid improved resume data. Please retry preview.

Error message

Invalid improved resume data. Please retry preview.

What it means

improve_resume_confirm_endpoint raises HTTP 400 when _validate_confirm_payload (comparing the improved payload against the original resume data) raises ValueError, meaning the client sent improved data inconsistent with the stored original or malformed relative to what preview produced.

Source

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

    feature_config = _load_config()
    enable_cover_letter = feature_config.get("enable_cover_letter", False)
    enable_outreach = feature_config.get("enable_outreach_message", False)
    enable_interview_prep = feature_config.get("enable_interview_prep", False)
    language = get_content_language()

    stage = "serialize_improved_data"
    detail = "Failed to confirm resume. Please try again."
    try:
        improved_data = request.improved_data.model_dump()
        improved_text = json.dumps(improved_data, indent=2)
        # NOTE: This endpoint relies on preview-hash validation to ensure the payload matches a prior preview.
        # Stronger guarantees would require server-side preview storage or re-running the improvement.
        try:
            _validate_confirm_payload(_get_original_resume_data(resume), improved_data)
        except ValueError as e:
            logger.warning("Resume confirm rejected: %s", e)
            raise HTTPException(
                status_code=400,
                detail="Invalid improved resume data. Please retry preview.",
            )
        preview_hashes = job.get("preview_hashes")
        allowed_hashes: set[str] = set()
        if isinstance(preview_hashes, dict):
            allowed_hashes.update(preview_hashes.values())
        elif isinstance(preview_hashes, list):
            allowed_hashes.update(
                [value for value in preview_hashes if isinstance(value, str)]
            )
        else:
            preview_hash = job.get("preview_hash")
            if isinstance(preview_hash, str):
                allowed_hashes.add(preview_hash)

        if not allowed_hashes:
            logger.warning(

View on GitHub (pinned to 116f9cc3b0)

Solutions

  1. Re-run the preview and confirm with the preview response's improved data unmodified (round-trip the exact object)
  2. Clear stale client state (cached preview payload) and start the tailoring flow again
  3. Check backend version mismatch: if the server was updated between preview and confirm, redo preview
  4. Inspect backend logs ('Resume confirm rejected: ...') to see which validation rule failed

Example fix

// before
const edited = {...previewData.improved};
edited.sections.push(newSection); // tampered
confirm({resume_id, job_id, improved_data: edited});
// after
confirm({resume_id, job_id, improved_data: previewData.improved}); // exact payload
Defensive patterns

Strategy: validation

Validate before calling

function isUntouchedPreview(preview: {improved: object}, toSend: object): boolean {
  // send the exact preview payload — deep-equal check before confirm
  return JSON.stringify(preview.improved) === JSON.stringify(toSend);
}
if (!isUntouchedPreview(preview, payload.improved_data)) payload.improved_data = preview.improved;

Type guard

function looksLikeImprovedResume(d: unknown): d is Record<string, unknown> {
  return typeof d === 'object' && d !== null &&
    Array.isArray((d as any).sections) && (d as any).sections.length > 0 &&
    typeof (d as any).contact === 'object';
}

Try / catch

try {
  await api.improveConfirm({resume_id, job_id, improved_data});
} catch (e) {
  if (e.response?.status === 400 && /Invalid improved resume data/.test(e.response.data?.detail ?? '')) {
    const fresh = await api.improvePreview({resume_id, job_id});
    await api.improveConfirm({resume_id, job_id, improved_data: fresh.improved});
  } else throw e;
}

Prevention

When it happens

Trigger: POST to improve/confirm whose improved_data fails payload validation — edited/tampered sections between preview and confirm, a changed schema, or confirming with hand-built JSON instead of the exact preview response body.

Common situations: Frontend mutated the preview response (e.g. injected a new section or rewrote IDs) before confirming; backend was upgraded mid-flow so validation rules differ; client retries confirm with an old payload against a newer backend.

Related errors


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