srbhr/Resume-Matcher · error · Error
Failed to update cover letter (status ${res.status}): ${text
Error message
Failed to update cover letter (status ${res.status}): ${text} What it means
updateCoverLetter() PATCHes /resumes/:id/cover-letter via apiPatch. Any non-OK HTTP response (4xx/5xx) causes this throw. The server's error body text and status code are embedded in the message so the caller can see why the backend rejected the save.
Source
Thrown at apps/frontend/lib/api/resume.ts:290
}
return await res.blob();
}
/** Deletes a resume by ID */
export async function deleteResume(resumeId: string): Promise<void> {
const res = await apiDelete(`/resumes/${encodeURIComponent(resumeId)}`);
if (!res.ok) {
const text = await res.text().catch(() => '');
throw new Error(`Failed to delete resume (status ${res.status}): ${text}`);
}
}
/** Updates the cover letter for a resume */
export async function updateCoverLetter(resumeId: string, content: string): Promise<void> {
const res = await apiPatch(`/resumes/${encodeURIComponent(resumeId)}/cover-letter`, { content });
if (!res.ok) {
const text = await res.text().catch(() => '');
throw new Error(`Failed to update cover letter (status ${res.status}): ${text}`);
}
}
/** Updates the outreach message for a resume */
export async function updateOutreachMessage(resumeId: string, content: string): Promise<void> {
const res = await apiPatch(`/resumes/${encodeURIComponent(resumeId)}/outreach-message`, {
content,
});
if (!res.ok) {
const text = await res.text().catch(() => '');
throw new Error(`Failed to update outreach message (status ${res.status}): ${text}`);
}
}
/** Renames a resume by updating its title */
export async function renameResume(resumeId: string, title: string): Promise<void> {
const res = await apiPatch(`/resumes/${encodeURIComponent(resumeId)}/title`, { title });
if (!res.ok) {View on GitHub (pinned to 116f9cc3b0)
Solutions
- Inspect the embedded status and body text in the message to identify the exact cause (401 vs 404 vs 400).
- If 401: refresh the session/token (re-login or token refresh) and retry the save.
- If 404: verify resumeId is valid and the resume still exists before saving.
- If 400/422: trim/validate the cover letter content against backend limits and re-save.
- If 5xx: retry after a delay; check backend health/logs if it persists.
- Persist unsaved content in local state so the user does not lose edits while fixing the cause.
Example fix
// before
await updateCoverLetter(resumeId, content);
// after
try {
await updateCoverLetter(resumeId, content);
} catch (err) {
if (String(err.message).includes('status 401')) {
await refreshSession();
await updateCoverLetter(resumeId, content);
} else {
notifyUser('Cover letter could not be saved. Your draft is kept locally.');
}
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!resumeId || typeof content !== 'string' || content.trim().length === 0) {
throw new Error('Cannot save cover letter: missing resumeId or empty content');
} Try / catch
try {
await updateCoverLetter(resumeId, content);
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
const status = msg.match(/status (\d+)/)?.[1];
if (status === '401') queueReauthAndRetry(() => updateCoverLetter(resumeId, content));
else showToast(`Save failed (${status ?? 'unknown'}): draft kept locally`);
} Prevention
- Validate resumeId and non-empty content before calling the API.
- Handle 401 globally (interceptor) with token refresh before requests reach this throw.
- Keep unsaved edits in local state/storage until save succeeds.
- Retry transient 5xx with backoff instead of failing immediately.
When it happens
Trigger: Calling updateCoverLetter(resumeId, content) when the API returns !res.ok: invalid/unknown resumeId (404), expired or missing auth session (401), validation rejection of the content payload (400/422), server error while persisting (500), or network/proxy failure surfaced as an HTTP error status.
Common situations: User edits a cover letter after the resume was deleted in another tab (404); JWT/session expired so the backend returns 401; content exceeds backend length limits or contains disallowed characters (400); backend deploy or DB outage causing 5xx during autosave.
Related errors
- 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
- Failed to generate 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/98e1ec5cc298bd2c.
Report an issue: GitHub.