{"record":{"id":"f7092b8377e9eac6","repo":"srbhr/Resume-Matcher","slug":"resume-id-is-required","errorCode":null,"errorMessage":"Resume ID is required.","messagePattern":"Resume ID is required\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/frontend/lib/api/resume.ts","lineNumber":99,"sourceCode":"  resume_id: string;\n  processing_status: 'pending' | 'processing' | 'ready' | 'failed';\n  is_master: boolean;\n}\n\ninterface ImproveResumeConfirmRequest {\n  resume_id: string;\n  job_id: string;\n  improved_data: ResumeData;\n  improvements: Array<{\n    suggestion: string;\n    lineNumber?: number | null;\n  }>;\n}\n\nfunction normalizeResumeId(resumeId: string): string {\n  const normalized = resumeId.trim();\n  if (!normalized) {\n    throw new Error('Resume ID is required.');\n  }\n  return normalized;\n}\n\nexport interface ResumeListItem {\n  resume_id: string;\n  filename: string | null;\n  is_master: boolean;\n  parent_id: string | null;\n  processing_status: 'pending' | 'processing' | 'ready' | 'failed';\n  created_at: string;\n  updated_at: string;\n  title?: string | null;\n  // Optional lightweight snippet of associated job description (populated client-side)\n  jobSnippet?: string;\n}\n\nasync function postImprove(","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/srbhr/Resume-Matcher/blob/116f9cc3b00e1ac91734a6c2679bf41ea64a0edc/apps/frontend/lib/api/resume.ts#L81-L117","documentation":"normalizeResumeId in apps/frontend/lib/api/resume.ts throws this synchronous Error when the supplied resumeId is empty or contains only whitespace after trimming. It is a client-side input guard used before every resume API call in this module, preventing pointless network requests with an invalid path parameter.","triggerScenarios":"Calling any resume API function (getResume, improveResume, uploadJobDescriptions, etc.) with resumeId = '' , '   ', or an undefined/null value coerced to an empty string — typically because state had not loaded yet or a route param was missing.","commonSituations":"A React component renders and fires the API call before the resume ID is fetched from the router/query; a deep link is missing the id query parameter; localStorage held an empty value after a cleared session; copy-paste dropped the ID.","solutions":["Check where the resumeId comes from (router params, query string, state) and confirm it is populated before invoking the API.","Gate the API call behind a loading/ready flag so it only runs once the ID is available.","Trim and truthiness-check the ID at the call site and show a user-facing 'resume not selected' state instead of calling the API.","Fix the data source that produced the empty ID (missing route param, empty localStorage entry)."],"exampleFix":"// before\nuseEffect(() => {\n  getResume(resumeId).then(setResume);\n}, [resumeId]);\n// after\nuseEffect(() => {\n  if (!resumeId?.trim()) return;\n  getResume(resumeId).then(setResume);\n}, [resumeId]);","handlingStrategy":"validation","validationCode":"const id = (resumeId ?? '').trim();\nif (!id) {\n  // skip the API call and render an empty/redirect state\n  return null;\n}","typeGuard":"function isValidResumeId(v: unknown): v is string {\n  return typeof v === 'string' && v.trim().length > 0;\n}","tryCatchPattern":"try {\n  const resume = await getResume(resumeId);\n} catch (e) {\n  if (e instanceof Error && e.message === 'Resume ID is required.') {\n    showError('No resume selected. Please choose a resume first.');\n    return;\n  }\n  throw e;\n}","preventionTips":["Never call resume APIs until the router/query param for the resume ID has resolved.","Treat empty IDs at the UI layer (disabled buttons, redirects) instead of letting the API layer throw.","Sanitize IDs read from localStorage/URL: trim and check truthiness before use."],"tags":["validation","input-error","client-side"],"backgroundTag":"missing-required-parameter","analyzedSha":"116f9cc3b00e1ac91734a6c2679bf41ea64a0edc","analyzedAt":"2026-08-28T22:51:40.999Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}