srbhr/Resume-Matcher · error · HTTPException
The associated job description was not found.
Error message
The associated job description was not found.
What it means
HTTP 404 raised by generate_cover_letter_endpoint when the improvement record exists and yields a job_id, but db.get_job(job_id) returns nothing — the job description that the resume was tailored against has been deleted or is otherwise missing. The AI prompt needs the job text, so generation is refused.
Source
Thrown at apps/backend/app/routers/resumes.py:1804
raise HTTPException(
status_code=400,
detail="Cover letter can only be generated for tailored resumes. "
"Please tailor this resume to a job description first.",
)
# 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,
detail="The associated job description was not found.",
)
# Get resume data
resume_data = resume.get("processed_data")
if not resume_data:
raise HTTPException(
status_code=400,
detail="Resume has no processed data. Please re-upload the resume.",
)
# Get language setting
language = get_content_language()
# Generate cover letter
try:
cover_letter_content = await generate_cover_letter(View on GitHub (pinned to 116f9cc3b0)
Solutions
- Re-create or re-import the missing job description, then re-tailor the resume so the improvement links to a valid job.
- Delete orphaned tailored resumes/improvements and re-tailor against an existing job.
- Restore the job record from backup if it was deleted accidentally.
- Add a cascade/consistency rule: deleting a job should archive or flag dependent tailored resumes.
Example fix
// before
await api.post(`/resumes/${resumeId}/generate-cover-letter`); // 404: job deleted
// after
const resume = await api.get(`/resumes/${resumeId}`);
const job = await api.get(`/jobs/${resume.data.jobId}`).catch(() => null);
if (!job) {
const re = await api.post(`/resumes/${resume.data.parentId}/tailor`, { jobId: existingJobId });
resumeId = re.data.id;
}
await api.post(`/resumes/${resumeId}/generate-cover-letter`); Defensive patterns
Strategy: fallback
Validate before calling
const improvement = await api.get(`/improvements?tailoredResumeId=${resumeId}`);
const job = improvement.data.length
? await api.get(`/jobs/${improvement.data[0].job_id}`).catch(() => null)
: null;
if (!job) throw new Error('Linked job missing — re-tailor against an existing job.'); Type guard
const jobStillExists = (improvement, job) => Boolean(improvement?.job_id) && job != null && job.id === improvement.job_id;
Try / catch
try {
await api.post(`/resumes/${resumeId}/generate-cover-letter`);
} catch (e) {
if (e.response?.status === 404 && /job description/.test(e.response.data?.detail ?? '')) {
notify('The job was deleted. Pick a job to re-tailor against.');
openJobPicker(resumeId);
} else throw e;
} Prevention
- Warn users before deleting a job that has tailored resumes depending on it.
- Periodically check improvements.job_id references resolve to existing jobs.
- Offer an in-flow 're-tailor' fallback when the linked job is gone.
When it happens
Trigger: Cover-letter generation for a tailored resume whose linked job was deleted (user removed the job, cascade delete didn't remove improvements, or job lives in another environment's DB).
Common situations: User deleted the job posting but kept the tailored resume, then tries to generate a cover letter; job import/sync pipeline removed the job; cross-environment ID reuse (improvement's job_id not present in current DB).
Related errors
AI-assisted analysis of srbhr/Resume-Matcher@116f9cc3b0 (2026-08-28).
Data as JSON: /api/errors/10199bacffa5f388.
Report an issue: GitHub.