{"record":{"id":"c74d4565d3acde39","repo":"slopus/happy","slug":"happy-session-session-id-is-missing-its-codex-t","errorCode":null,"errorMessage":"Happy session ${session.id} is missing its Codex thread ID.","messagePattern":"Happy session (.+?) is missing its Codex thread ID\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/happy-cli/src/resume/handleResumeCommand.ts","lineNumber":59,"sourceCode":"}\n\nfunction resolveFlavor(metadata: Metadata): 'codex' | 'claude' | null {\n    if (metadata.flavor === 'codex' || metadata.codexThreadId) {\n        return 'codex';\n    }\n    if (metadata.flavor === 'claude' || metadata.claudeSessionId) {\n        return 'claude';\n    }\n    return null;\n}\n\nexport function buildResumeLaunch(session: ResumableHappySession, options: ResumeLaunchOptions = {}): ResumeLaunch {\n    const { metadata } = session;\n    const flavor = resolveFlavor(metadata);\n\n    if (flavor === 'codex') {\n        if (!metadata.codexThreadId) {\n            throw new Error(`Happy session ${session.id} is missing its Codex thread ID.`);\n        }\n        const args = ['codex', '--resume', metadata.codexThreadId];\n        if (options.startedBy) {\n            args.push('--started-by', options.startedBy);\n        }\n        return {\n            cwd: metadata.path,\n            args,\n        };\n    }\n\n    if (flavor === 'claude') {\n        if (!metadata.claudeSessionId) {\n            throw new Error(`Happy session ${session.id} is missing its Claude session ID.`);\n        }\n        const args = ['claude'];\n        if (options.claudeStartingMode) {\n            args.push('--happy-starting-mode', options.claudeStartingMode);","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/slopus/happy/blob/b824cd0a4681d41af631a8e422a813873e4455b0/packages/happy-cli/src/resume/handleResumeCommand.ts#L41-L77","documentation":"buildResumeLaunch throws this when a session's resolved flavor is 'codex' but its persisted metadata lacks codexThreadId. Resuming a Codex session requires the original thread ID to pass to `codex --resume <thread-id>`; without it the CLI cannot reconstruct the session.","triggerScenarios":"Calling buildResumeLaunch (directly or via handleResumeCommand/launch) with a ResumableHappySession whose metadata.flavor resolves to 'codex' while metadata.codexThreadId is undefined/null — e.g. metadata was written by an older CLI version before Codex support recorded thread IDs.","commonSituations":"Sessions created before a Codex-supporting happy release; metadata encrypted before codexThreadId was added to ResumableMetadataSchema; hand-edited or partially synced sessions file; session started via a path that never captured the Codex thread ID.","solutions":["Start a new Happy session with the current CLI version so codexThreadId is captured in metadata","Check that the session was genuinely started with Codex support enabled in the installed happy-cli version","Upgrade happy-cli and re-sync/re-encrypt the session metadata if your version predates codexThreadId","Resume the session manually with `codex --resume <thread-id>` if you can find the thread ID under ~/.codex"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"function canResumeCodex(s: ResumableHappySession): boolean {\n  return resolveFlavor(s.metadata) === 'codex' && typeof s.metadata.codexThreadId === 'string' && s.metadata.codexThreadId.length > 0;\n}","typeGuard":"function hasCodexThreadId(m: Metadata): m is Metadata & { codexThreadId: string } {\n  return typeof (m as any).codexThreadId === 'string' && (m as any).codexThreadId.length > 0;\n}","tryCatchPattern":"try {\n  const launch = buildResumeLaunch(session);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('missing its Codex thread ID')) {\n    console.error('This Codex session cannot be resumed; start a new session with an up-to-date CLI.');\n    return;\n  }\n  throw e;\n}","preventionTips":["Keep happy-cli up to date so codexThreadId is always captured","Check metadata.codexThreadId before attempting resume of a codex-flavored session","Avoid hand-editing encrypted session metadata","Re-create very old Codex sessions with the current CLI"],"tags":["codex","metadata","resume","missing-field"],"backgroundTag":"missing-session-metadata","analyzedSha":"b824cd0a4681d41af631a8e422a813873e4455b0","analyzedAt":"2026-08-31T23:12:36.205Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}