{"record":{"id":"6a59e0da48ebb291","repo":"srbhr/Resume-Matcher","slug":"master-resume-id-is-missing","errorCode":null,"errorMessage":"Master resume ID is missing.","messagePattern":"Master resume ID is missing\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/frontend/app/(default)/tailor/page.tsx","lineNumber":126,"sourceCode":"        if (!cancelled) {\n          setPromptLoading(false);\n        }\n      }\n    };\n\n    loadPromptConfig();\n    return () => {\n      cancelled = true;\n    };\n  }, []);\n\n  const handleTextareaKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n    if (e.key === 'Enter') e.stopPropagation();\n  };\n\n  const buildConfirmPayload = (result: ImprovedResult) => {\n    if (!masterResumeId) {\n      throw new Error('Master resume ID is missing.');\n    }\n    const resumePreview = result.data.resume_preview;\n    if (!resumePreview || typeof resumePreview !== 'object' || Array.isArray(resumePreview)) {\n      throw new Error('Resume preview data is invalid.');\n    }\n    const previewRecord = resumePreview as unknown as Record<string, unknown>;\n    if (\n      !previewRecord.personalInfo ||\n      typeof previewRecord.personalInfo !== 'object' ||\n      Array.isArray(previewRecord.personalInfo)\n    ) {\n      throw new Error('Resume preview data is invalid.');\n    }\n    return {\n      resume_id: masterResumeId,\n      job_id: result.data.job_id,\n      improved_data: resumePreview as ResumeData,\n      improvements:","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/srbhr/Resume-Matcher/blob/116f9cc3b00e1ac91734a6c2679bf41ea64a0edc/apps/frontend/app/(default)/tailor/page.tsx#L108-L144","documentation":"buildConfirmPayload in apps/frontend/app/(default)/tailor/page.tsx throws this when the client-side masterResumeId state is falsy (null/empty) at the moment the user confirms the AI-improved resume preview. masterResumeId is initialized to null and only set from localStorage key 'master_resume_id' in a useEffect; if the key is absent the component redirects to /dashboard, but a confirm click can still race the effect or run with an empty stored value. The guard exists because the confirm payload requires resume_id to link the improved resume back to its master.","triggerScenarios":"Calling confirmAndNavigate/buildConfirmPayload while masterResumeId is still null: (1) the 'master_resume_id' localStorage key was never set (user navigated straight to /tailor without uploading a resume in /builder), (2) the confirm action fires before the hydration useEffect finishes, (3) localStorage was cleared (private browsing, storage eviction) between mount and confirm.","commonSituations":"Deep-linking or refreshing /tailor after clearing site data; opening the page in an incognito window where localStorage writes don't persist; a stale tab where another tab's 'reset database' cleared the ID; tests clicking confirm before effects run.","solutions":["Upload/select a master resume first (via /builder or /dashboard) so 'master_resume_id' exists in localStorage before visiting /tailor.","Guard the confirm button: disable it (or show the dashboard redirect) until masterResumeId is set.","In buildConfirmPayload's caller, catch this error and re-run the localStorage check / redirect to /dashboard instead of crashing.","Clear the site's localStorage or use a normal (non-private) window if storage was the cause."],"exampleFix":"// before\nconst buildConfirmPayload = (result: ImprovedResult) => {\n  if (!masterResumeId) {\n    throw new Error('Master resume ID is missing.');\n  }\n  ...\n};\n// after\nconst buildConfirmPayload = (result: ImprovedResult) => {\n  const storedId = masterResumeId ?? localStorage.getItem('master_resume_id');\n  if (!storedId) {\n    router.push('/dashboard');\n    throw new Error('Master resume ID is missing.');\n  }\n  ...\n};","handlingStrategy":"try-catch","validationCode":"function canConfirm(): boolean {\n  const id = typeof window !== 'undefined' ? localStorage.getItem('master_resume_id') : null;\n  return Boolean(id);\n}\n// disable the confirm action until canConfirm() is true","typeGuard":"function hasMasterResumeId(id: string | null): id is string {\n  return typeof id === 'string' && id.length > 0;\n}","tryCatchPattern":"try {\n  await confirmAndNavigate(result);\n} catch (err) {\n  if (err instanceof Error && err.message === 'Master resume ID is missing.') {\n    localStorage.removeItem('master_resume_id');\n    router.push('/dashboard');\n    return;\n  }\n  throw err;\n}","preventionTips":["Never deep-link to /tailor without first storing 'master_resume_id' via the builder/dashboard flow.","Render the confirm button only after masterResumeId state is hydrated (non-null).","Handle the storage/unload events if localStorage can be cleared while the page is open.","In tests, seed localStorage before mounting and wait for effects before clicking confirm."],"tags":["react","localstorage","state","client-side","guard-clause"],"backgroundTag":"missing-localstorage-key","analyzedSha":"116f9cc3b00e1ac91734a6c2679bf41ea64a0edc","analyzedAt":"2026-08-28T22:51:40.999Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}