{"record":{"id":"e487afc83db41204","repo":"slopus/happy","slug":"happy-session-id-is-required-happy-resume-sessio-e487af","errorCode":null,"errorMessage":"Happy session ID is required: happy resume <session-id>","messagePattern":"Happy session ID is required: happy resume <session-id>","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/happy-cli/src/resume/resolveHappySession.ts","lineNumber":62,"sourceCode":"\nexport type ResumableHappySession = {\n    id: string;\n    active: boolean;\n    metadata: Metadata;\n};\n\nexport type ReconnectableHappySession = ResumableHappySession & {\n    seq: number;\n    metadataVersion: number;\n    agentStateVersion: number;\n    encryptionKey: Uint8Array;\n    encryptionVariant: 'legacy' | 'dataKey';\n};\n\nexport function resolveSessionRecordByPrefix<T extends { id: string }>(records: T[], sessionId: string): T {\n    const trimmed = sessionId.trim();\n    if (!trimmed) {\n        throw new Error('Happy session ID is required: happy resume <session-id>');\n    }\n\n    const matches = records.filter((record) => record.id.startsWith(trimmed));\n    if (matches.length === 0) {\n        throw new Error(`No Happy session found matching \"${trimmed}\"`);\n    }\n    if (matches.length > 1) {\n        throw new Error(`Ambiguous Happy session \"${trimmed}\" matches ${matches.length} sessions. Be more specific.`);\n    }\n    return matches[0];\n}\n\nfunction decryptBoxBundle(bundle: Uint8Array, recipientSecretKey: Uint8Array): Uint8Array | null {\n    if (bundle.length < 56) {\n        return null;\n    }\n\n    const ephemeralPublicKey = bundle.slice(0, 32);","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/slopus/happy/blob/b824cd0a4681d41af631a8e422a813873e4455b0/packages/happy-cli/src/resume/resolveHappySession.ts#L44-L80","documentation":"resolveSessionRecordByPrefix matches a user-supplied session ID prefix against known Happy session records. Before filtering it trims the input, and if nothing remains it throws this error because an empty prefix would match every (or no) session and resume is impossible without an ID. The message doubles as usage guidance pointing to `happy resume <session-id>`.","triggerScenarios":"Calling resolveSessionRecordByPrefix(records, sessionId) with an empty string, a whitespace-only string, or indirectly via happy resume when no session-id argument is provided.","commonSituations":"Running `happy resume` with no argument in a shell script or CI pipeline; a wrapper script losing the argument due to unquoted variable expansion ($1 unset); copy-paste that dropped the ID.","solutions":["Pass a session ID: run `happy resume <session-id>` with at least a non-empty prefix of the session ID.","Check the wrapper/script for an unset or empty variable holding the session ID and quote it: happy resume \"$SESSION_ID\".","List available sessions first to find a valid ID, then resume with that ID."],"exampleFix":"// before\nconst id = process.argv[2] ?? '';\nawait resolveHappySession(id);\n// after\nconst id = process.argv[2]?.trim();\nif (!id) {\n  console.error('Usage: happy resume <session-id>');\n  process.exit(1);\n}\nawait resolveHappySession(id);","handlingStrategy":"validation","validationCode":"const id = (sessionId ?? '').trim();\nif (!id) throw new Error('Usage: happy resume <session-id>');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always require/parse the session-id argument explicitly before invoking resume.","Quote shell variables so an unset $1 doesn't collapse to an empty argument.","Validate arguments in wrapper scripts and print usage on empty input."],"tags":["cli","argument-validation","session-resume"],"backgroundTag":"missing-required-argument","analyzedSha":"b824cd0a4681d41af631a8e422a813873e4455b0","analyzedAt":"2026-08-31T23:12:36.205Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}