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
- Only call this endpoint for tailored resumes — check parent_id in the resume object before calling.
- If you need a job link for an original resume, tailor it against a job first, then use the tailored copy's id.
- 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
- Check parent_id before showing any 'view job description' UI action.
- Label resumes as original vs tailored in the client data model.
- Understand the endpoint contract: it is scoped to tailored resumes only.
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
- Cover letter can only be generated for tailored resumes. Ple
- Outreach message can only be generated for tailored resumes.
- Interview preparation can only be generated for tailored res
- Unsupported UI language: {request.ui_language}. Supported: {
- Unsupported content language: {request.content_language}. Su
AI-assisted analysis of srbhr/Resume-Matcher@116f9cc3b0 (2026-08-28).
Data as JSON: /api/errors/e55a795f68d61d54.
Report an issue: GitHub.