{"record":{"id":"6289efe71276b846","repo":"srbhr/Resume-Matcher","slug":"failed-to-generate-cover-letter-please-try-again","errorCode":null,"errorMessage":"Failed to generate cover letter. Please try again.","messagePattern":"Failed to generate cover letter\\. Please try again\\.","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"apps/backend/app/routers/resumes.py","lineNumber":1827,"sourceCode":"    # Get resume data\n    resume_data = resume.get(\"processed_data\")\n    if not resume_data:\n        raise HTTPException(\n            status_code=400,\n            detail=\"Resume has no processed data. Please re-upload the resume.\",\n        )\n\n    # Get language setting\n    language = get_content_language()\n\n    # Generate cover letter\n    try:\n        cover_letter_content = await generate_cover_letter(\n            resume_data, job[\"content\"], language\n        )\n    except Exception as e:\n        logger.error(f\"Cover letter generation failed: {e}\")\n        raise HTTPException(\n            status_code=500,\n            detail=\"Failed to generate cover letter. Please try again.\",\n        )\n\n    # Save to resume record\n    await db.update_resume(resume_id, {\"cover_letter\": cover_letter_content})\n\n    return GenerateContentResponse(\n        content=cover_letter_content,\n        message=\"Cover letter generated successfully\",\n    )\n\n\n@router.post(\"/{resume_id}/generate-outreach\", response_model=GenerateContentResponse)\nasync def generate_outreach_endpoint(resume_id: str) -> GenerateContentResponse:\n    \"\"\"Generate an outreach message on-demand for an existing tailored resume.\n\n    This endpoint allows users to generate a cold outreach message after a resume","sourceCodeStart":1809,"sourceCodeEnd":1845,"githubUrl":"https://github.com/srbhr/Resume-Matcher/blob/116f9cc3b00e1ac91734a6c2679bf41ea64a0edc/apps/backend/app/routers/resumes.py#L1809-L1845","documentation":"This 500 error is raised by the generate_cover_letter_endpoint when the call to generate_cover_letter() (an AI/LLM-backed helper) throws any exception. The endpoint wraps the generation call in a broad try/except, logs the underlying cause, and returns a generic retry-able message so internal AI errors are not leaked to the client.","triggerScenarios":"POSTing to the cover-letter generation route with valid resume_id/job context, but generate_cover_letter() fails — e.g. LLM API timeout, rate limit, invalid API key, malformed resume_data, or content that the model rejects.","commonSituations":"Expired or missing LLM API credentials in the environment, upstream provider outage or 429 rate limiting, oversized resume/job-description content exceeding the model context window, or network egress blocked from the backend.","solutions":["Check backend logs for 'Cover letter generation failed: <e>' to see the real cause","Verify the LLM provider API key and quota in the backend environment","Retry the request — transient provider timeouts/rate limits usually resolve","Reduce resume/job description size if the payload may exceed model limits"],"exampleFix":"// before\ncurl -X POST /api/resumes/{id}/cover-letter  # 500 generic\n// after\n# inspect server logs first, e.g.\ndocker logs backend | grep 'Cover letter generation failed'","handlingStrategy":"try-catch","validationCode":"const resume = await getResume(resumeId);\nconst job = await getJob(jobId);\nif (!resume?.processedData || !job?.content) throw new Error('Missing inputs for cover letter generation');","typeGuard":null,"tryCatchPattern":"try {\n  await api.generateCoverLetter(resumeId);\n} catch (e) {\n  if (e.response?.status === 500) {\n    // inspect server logs / retry after checking LLM provider health\n    await sleep(1000);\n    return retryOnce(() => api.generateCoverLetter(resumeId));\n  }\n  throw e;\n}","preventionTips":["Monitor LLM provider status/quotas before batch generation","Log the underlying exception server-side and alert on it","Set explicit timeouts and retries around the AI helper call","Validate resume_data and job content size before sending to the model"],"tags":["http-500","ai-generation","backend"],"backgroundTag":"llm-generation-failed","analyzedSha":"116f9cc3b00e1ac91734a6c2679bf41ea64a0edc","analyzedAt":"2026-08-28T22:51:40.999Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}