slopus/happy · error
Happy session ${session.id} is missing its Claude session ID
Error message
Happy session ${session.id} is missing its Claude session ID. What it means
buildResumeLaunch throws this when a session's resolved flavor is 'claude' but its metadata lacks claudeSessionId. Resuming a Claude session requires the original Claude session ID so the CLI can spawn `claude` pointed at that session; without it resume cannot proceed.
Source
Thrown at packages/happy-cli/src/resume/handleResumeCommand.ts:73
const flavor = resolveFlavor(metadata);
if (flavor === 'codex') {
if (!metadata.codexThreadId) {
throw new Error(`Happy session ${session.id} is missing its Codex thread ID.`);
}
const args = ['codex', '--resume', metadata.codexThreadId];
if (options.startedBy) {
args.push('--started-by', options.startedBy);
}
return {
cwd: metadata.path,
args,
};
}
if (flavor === 'claude') {
if (!metadata.claudeSessionId) {
throw new Error(`Happy session ${session.id} is missing its Claude session ID.`);
}
const args = ['claude'];
if (options.claudeStartingMode) {
args.push('--happy-starting-mode', options.claudeStartingMode);
}
if (options.startedBy) {
args.push('--started-by', options.startedBy);
}
args.push('--resume', metadata.claudeSessionId);
return {
cwd: metadata.path,
args,
};
}
throw new Error(`Happy session ${session.id} uses unsupported flavor "${metadata.flavor ?? 'unknown'}".`);
}
View on GitHub (pinned to b824cd0a46)
Solutions
- Start a new Happy session with the current CLI so claudeSessionId is persisted
- Verify the installed happy-cli version supports capturing claudeSessionId and upgrade if not
- Resume manually with `claude --resume <session-id>` if you can locate the ID in ~/.claude/projects
- Delete the stale session record if it is unrecoverable
Defensive patterns
Strategy: validation
Validate before calling
function canResumeClaude(s: ResumableHappySession): boolean {
return resolveFlavor(s.metadata) === 'claude' && typeof s.metadata.claudeSessionId === 'string' && s.metadata.claudeSessionId.length > 0;
} Type guard
function hasClaudeSessionId(m: Metadata): m is Metadata & { claudeSessionId: string } {
return typeof (m as any).claudeSessionId === 'string' && (m as any).claudeSessionId.length > 0;
} Try / catch
try {
const launch = buildResumeLaunch(session);
} catch (e) {
if (e instanceof Error && e.message.includes('missing its Claude session ID')) {
console.error('This Claude session cannot be resumed; start a new session or resume manually via `claude --resume`.');
return;
}
throw e;
} Prevention
- Keep happy-cli current so claudeSessionId is persisted at session start
- Validate metadata.claudeSessionId before resuming a claude-flavored session
- Do not strip fields when migrating or syncing session metadata
- Filter session lists to sessions with complete metadata before offering resume
When it happens
Trigger: Calling buildResumeLaunch (directly or via handleResumeCommand/launch) with a ResumableHappySession whose metadata.flavor resolves to 'claude' while metadata.claudeSessionId is undefined/null — typically metadata persisted before claudeSessionId was recorded.
Common situations: Sessions created by older happy-cli versions before claudeSessionId was included; metadata corruption or truncated decryption; sessions started outside the happy wrapper and later registered without full metadata.
Related errors
- Happy session ${session.id} is missing its Codex thread ID.
- Happy session ${sessionId} is missing resumable metadata.
- Metadata version mismatch
- Metadata version mismatch
- Failed to resume Codex thread ${opts.threadId}: ${reason}
AI-assisted analysis of slopus/happy@b824cd0a46 (2026-08-31).
Data as JSON: /api/errors/48737fbad1ba1c5d.
Report an issue: GitHub.