srbhr/Resume-Matcher · error · Error

Failed to rename resume (status ${res.status}): ${text}

Error message

Failed to rename resume (status ${res.status}): ${text}

What it means

renameResume() PATCHes /resumes/:id/title via apiPatch. Any non-OK HTTP response causes this throw with status and body text included in the message. It is thrown for every failed title update, whether auth-, validation-, or server-related.

Source

Thrown at apps/frontend/lib/api/resume.ts:310

}

/** 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) {
    const text = await res.text().catch(() => '');
    throw new Error(`Failed to rename resume (status ${res.status}): ${text}`);
  }
}

/** Downloads cover letter as PDF */
export function getCoverLetterPdfUrl(
  resumeId: string,
  pageSize: 'A4' | 'LETTER' = 'A4',
  locale?: Locale
): string {
  const normalizedId = normalizeResumeId(resumeId);
  const params = new URLSearchParams({ pageSize });
  if (locale) {
    params.set('lang', locale);
  }
  return `${API_BASE}/resumes/${encodeURIComponent(normalizedId)}/cover-letter/pdf?${params.toString()}`;
}

export async function downloadCoverLetterPdf(

View on GitHub (pinned to 116f9cc3b0)

Solutions

  1. Parse the status/body from the message to determine the failure class.
  2. If 400/422: validate the title client-side (non-empty, within length limit) and retry.
  3. If 401: refresh the session and re-attempt the rename.
  4. If 404: verify the resume still exists before renaming.
  5. If 5xx: retry with backoff; check backend logs if repeated.
  6. Revert the UI title to the previous value on failure so state stays consistent.

Example fix

// before
await renameResume(resumeId, title);

// after
const trimmed = title.trim();
if (!trimmed || trimmed.length > 200) {
  notifyUser('Title must be 1-200 characters.');
  return;
}
try {
  await renameResume(resumeId, trimmed);
} catch (err) {
  setTitle(previousTitle);
  notifyUser(`Rename failed: ${err.message}`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

const trimmed = title.trim();
if (!trimmed || trimmed.length > 200) {
  throw new Error('Title must be between 1 and 200 characters');
}

Try / catch

try {
  await renameResume(resumeId, trimmedTitle);
} catch (err) {
  const msg = err instanceof Error ? err.message : String(err);
  setTitle(previousTitle); // rollback optimistic UI
  notifyUser(msg.includes('status 404') ? 'Resume no longer exists' : `Rename failed: ${msg}`);
}

Prevention

When it happens

Trigger: Calling renameResume(resumeId, title) when the API returns !res.ok: unknown/deleted resumeId (404), expired session (401), empty or oversized title rejected (400/422), or backend error persisting the title (500).

Common situations: User submits an empty title from the inline editor (400); resume was deleted concurrently so the rename 404s; auth cookie/token expired (401); unique-constraint or DB failure on the backend (500).

Related errors


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