srbhr/Resume-Matcher · error · Error
Failed to generate cover letter (status ${res.status}): ${te
Error message
Failed to generate cover letter (status ${res.status}): ${text} What it means
generateCoverLetter() POSTs to /resumes/:id/generate-cover-letter via apiPost and throws on any non-OK response. This endpoint is typically AI/LLM-backed, so failures include both standard auth/validation errors and generation-side failures reported as 4xx/5xx.
Source
Thrown at apps/frontend/lib/api/resume.ts:347
resumeId: string,
pageSize: 'A4' | 'LETTER' = 'A4',
locale?: Locale
): Promise<Blob> {
const url = getCoverLetterPdfUrl(resumeId, pageSize, locale);
const res = await apiFetch(url);
if (!res.ok) {
const text = await res.text().catch(() => '');
throw new Error(`Failed to download cover letter (status ${res.status}): ${text}`);
}
return await res.blob();
}
/** Generates a cover letter on-demand for a tailored resume */
export async function generateCoverLetter(resumeId: string): Promise<string> {
const res = await apiPost(`/resumes/${encodeURIComponent(resumeId)}/generate-cover-letter`, {});
if (!res.ok) {
const text = await res.text().catch(() => '');
throw new Error(`Failed to generate cover letter (status ${res.status}): ${text}`);
}
const data = await res.json();
return data.content;
}
/** Generates an outreach message on-demand for a tailored resume */
export async function generateOutreachMessage(resumeId: string): Promise<string> {
const res = await apiPost(`/resumes/${encodeURIComponent(resumeId)}/generate-outreach`, {});
if (!res.ok) {
const text = await res.text().catch(() => '');
throw new Error(`Failed to generate outreach message (status ${res.status}): ${text}`);
}
const data = await res.json();
return data.content;
}
/** Generates interview preparation on-demand for a tailored resume */
export async function generateInterviewPrep(resumeId: string): Promise<InterviewPrepData> {View on GitHub (pinned to 116f9cc3b0)
Solutions
- Read the status/body in the message: 429 means rate-limited (wait and retry), 401 means re-authenticate, 404 means check the resume.
- If 401: refresh the session and retry generation.
- If 429/502/503: retry with exponential backoff; check AI provider status/quota.
- If 404/400: verify the resume exists and contains the content generation depends on.
- Disable the generate button while in flight and on failure show a retryable error to the user.
Example fix
// before
const content = await generateCoverLetter(resumeId);
// after
try {
const content = await generateCoverLetter(resumeId);
} catch (err) {
if (String(err.message).match(/status (429|502|503)/)) {
await delay(2000);
return generateCoverLetter(resumeId); // retry once
}
notifyUser('Cover letter generation failed. Please try again shortly.');
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!resumeId) {
throw new Error('Cannot generate cover letter: resumeId is required');
} Try / catch
try {
const { content } = await generateCoverLetterSafe(resumeId);
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
if (/status (429|502|503|504)/.test(msg)) {
await retryWithBackoff(() => generateCoverLetter(resumeId), 3);
} else if (msg.includes('status 401')) {
promptRelogin();
} else {
notifyUser('Generation failed. Please try again shortly.');
}
} Prevention
- Implement retry with exponential backoff for 429/5xx from AI-backed endpoints.
- Disable the generate button while a request is in flight to avoid duplicate calls.
- Refresh sessions before long generation workflows to avoid 401s.
- Set a client-side timeout slightly below the gateway timeout and treat timeouts as retryable.
When it happens
Trigger: Calling generateCoverLetter(resumeId) when the API returns !res.ok: no resume or tailored content to base generation on (404), expired auth (401), upstream AI provider failure or rate limit surfaced as 429/502/503, or request-body/route mismatch (400/405).
Common situations: LLM provider outage or quota exhaustion causing 429/502; session expired when the user clicks 'generate' (401); resume lacks the base content required for generation (404/400); long generation exceeding a gateway timeout (504).
Related errors
- Failed to update cover letter (status ${res.status}): ${text
- Failed to update outreach message (status ${res.status}): ${
- Failed to rename resume (status ${res.status}): ${text}
- Failed to download cover letter (status ${res.status}): ${te
- Upload failed for ${fileToUpload.file.name}. Status: ${respo
AI-assisted analysis of srbhr/Resume-Matcher@116f9cc3b0 (2026-08-28).
Data as JSON: /api/errors/181b9764d7e64682.
Report an issue: GitHub.