srbhr/Resume-Matcher · warning · HTTPException

Job description is only available for tailored resumes.

Error message

Job description is only available for tailored resumes.

What it means

HTTP 400 raised when the resume exists but has no parent_id, meaning it is an original (untailored) resume. Job descriptions are only stored for tailored resumes created from a job context, so the endpoint rejects originals by design.

Source

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

        message="Interview preparation generated successfully",
    )


@router.get("/{resume_id}/job-description")
async def get_job_description_for_resume(resume_id: str) -> dict:
    """Get the job description used to tailor this resume.

    This endpoint retrieves the original job description that was used
    to tailor a resume. Only works for tailored resumes (those with parent_id).
    """
    # Get the resume
    resume = await db.get_resume(resume_id)
    if not resume:
        raise HTTPException(status_code=404, detail="Resume not found")

    # Check if it's a tailored resume (has parent_id)
    if not resume.get("parent_id"):
        raise HTTPException(
            status_code=400,
            detail="Job description is only available for tailored resumes.",
        )

    # Get improvement record to find the job_id
    improvement = await db.get_improvement_by_tailored_resume(resume_id)
    if not improvement:
        raise HTTPException(
            status_code=400,
            detail="No job context found for this resume. "
            "The resume may have been created before job tracking was implemented.",
        )

    # Get the job description
    job = await db.get_job(improvement["job_id"])
    if not job:
        raise HTTPException(
            status_code=404,

View on GitHub (pinned to 116f9cc3b0)

Solutions

  1. Only call this endpoint for tailored resumes — check parent_id in the resume object before calling.
  2. If you need a job link for an original resume, tailor it against a job first, then use the tailored copy's id.
  3. Hide/disable the job-description action in the UI when parent_id is missing.

Example fix

// before
const res = await fetch(`/api/resumes/${resume.id}/job-description`);
// after
if (resume.parent_id) {
  const res = await fetch(`/api/resumes/${resume.id}/job-description`);
}
Defensive patterns

Strategy: type-guard

Validate before calling

const resume = await getResume(id);
if (!resume?.parent_id) {
  throw new SkipError('not a tailored resume — job description endpoint not applicable');
}

Type guard

function isTailoredResume(r) {
  return r != null && typeof r.parent_id === 'string' && r.parent_id.length > 0;
}

Try / catch

try {
  const jd = await getJobDescription(resumeId);
} catch (e) {
  if (e.status === 400 && /tailored resumes/i.test(e.detail)) {
    return null; // original resume: no job description exists by design
  }
  throw e;
}

Prevention

When it happens

Trigger: Request the job description for a resume that was uploaded directly (not produced by the tailoring flow), so resume.parent_id is absent/null.

Common situations: UI showing the 'view job description' action on non-tailored resumes; client confusing original vs tailored resume ids after duplication; older data model without parent_id backfilled as null.

Related errors


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