srbhr/Resume-Matcher · error · HTTPException

Job description not found

Error message

Job description not found

What it means

improve_resume_preview_endpoint raises HTTP 404 when db.get_job(request.job_id) finds no job description. After the resume is validated, the preview needs a matching persisted job description to tailor against.

Source

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

    return ResumeListResponse(request_id=str(uuid4()), data=summaries)


@router.post("/improve/preview", response_model=ImproveResumeResponse)
async def improve_resume_preview_endpoint(
    request: ImproveResumeRequest,
) -> ImproveResumeResponse:
    """Preview a tailored resume without persisting it.

    The response includes resume_preview data but leaves resume_id null.
    """
    resume = await db.get_resume(request.resume_id)
    if not resume:
        raise HTTPException(status_code=404, detail="Resume not found")

    job = await db.get_job(request.job_id)
    if not job:
        raise HTTPException(status_code=404, detail="Job description not found")

    language = get_content_language()
    prompt_id = request.prompt_id or _get_default_prompt_id()

    stage = "load_job_keywords"
    detail = "Failed to preview resume. Please try again."
    try:
        return await asyncio.wait_for(
            _improve_preview_flow(
                request=request,
                resume=resume,
                job=job,
                language=language,
                prompt_id=prompt_id,
            ),
            timeout=settings.request_timeout_seconds,
        )
    except asyncio.TimeoutError:

View on GitHub (pinned to 116f9cc3b0)

Solutions

  1. Re-create or re-save the job description and use its current job_id in the preview request
  2. Verify the job exists (GET /jobs/{job_id}) before calling preview
  3. Ensure the client's job_id state is refreshed after any job deletion
  4. Check both IDs belong to the same database/environment

Example fix

// before
cPreview(job.id) // job was deleted earlier
// after
if (!(await jobExists(job.id))) job = await createJob(jdText);
preview({resume_id: resume.id, job_id: job.id})
Defensive patterns

Strategy: validation

Validate before calling

async function requireJob(id: string) {
  const res = await fetch(`/api/jobs/${id}`);
  if (!res.ok) throw new Error('Job description missing — re-save it before tailoring');
  return res.json();
}
await requireJob(previewPayload.job_id); // before calling preview

Type guard

function hasJobRef(r: unknown): r is {job_id: string} {
  return typeof r === 'object' && r !== null &&
    typeof (r as any).job_id === 'string' && (r as any).job_id.length > 0;
}

Try / catch

try {
  await api.improvePreview({resume_id, job_id});
} catch (e) {
  if (e.response?.status === 404 && /job description/i.test(e.response.data?.detail ?? '')) {
    openJobEditorToResave();
  } else throw e;
}

Prevention

When it happens

Trigger: POST to improve/preview with a job_id that was deleted, never saved, or created after the resume record (IDs from different DB sessions); job_id omitted/empty and resolved to a non-existent record.

Common situations: Job description deleted via the jobs UI while the resume editor stayed open; seeding scripts created resumes but not jobs; frontend cached an old job list; wrong environment's database.

Related errors


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