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

  1. Start a new Happy session with the current CLI so claudeSessionId is persisted
  2. Verify the installed happy-cli version supports capturing claudeSessionId and upgrade if not
  3. Resume manually with `claude --resume <session-id>` if you can locate the ID in ~/.claude/projects
  4. 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

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


AI-assisted analysis of slopus/happy@b824cd0a46 (2026-08-31). Data as JSON: /api/errors/48737fbad1ba1c5d. Report an issue: GitHub.