{"record":{"id":"c8bedbb0b00194a4","repo":"slopus/happy","slug":"failed-to-decrypt-metadata-for-happy-session-ses","errorCode":null,"errorMessage":"Failed to decrypt metadata for Happy session ${session.id}","messagePattern":"Failed to decrypt metadata for Happy session (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/happy-cli/src/resume/resolveHappySession.ts","lineNumber":126,"sourceCode":"            variant: 'dataKey',\n        };\n    }\n\n    return {\n        key: credentials.secret,\n        variant: 'legacy',\n    };\n}\n\nfunction decryptSessionMetadata(session: RawSession, credentials: LocalHappyAgentCredentials): Metadata {\n    const encryption = resolveSessionEncryption(session, credentials);\n    const encryptedMetadata = decodeBase64(session.metadata);\n    const metadata = encryption.variant === 'dataKey'\n        ? decryptWithDataKey(encryptedMetadata, encryption.key)\n        : decryptLegacy(encryptedMetadata, encryption.key);\n\n    if (!metadata) {\n        throw new Error(`Failed to decrypt metadata for Happy session ${session.id}`);\n    }\n\n    return parseResumableMetadata(session.id, metadata);\n}\n\nasync function fetchSessions(credentials: LocalHappyAgentCredentials): Promise<RawSession[]> {\n    try {\n        const response = await axios.get(`${configuration.serverUrl}/v1/sessions`, {\n            headers: {\n                Authorization: `Bearer ${credentials.token}`,\n                'X-Happy-Client': `cli-coding-session/${configuration.currentCliVersion}`,\n            },\n        });\n        return (response.data as { sessions: RawSession[] }).sessions;\n    } catch (error) {\n        if (error instanceof AxiosError) {\n            if (error.response?.status === 401) {\n                throw new Error('Happy session lookup authentication expired for legacy account credentials.');","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/slopus/happy/blob/b824cd0a4681d41af631a8e422a813873e4455b0/packages/happy-cli/src/resume/resolveHappySession.ts#L108-L144","documentation":"decryptSessionMetadata decrypts the session's encrypted metadata blob using the resolved RecordEncryption (either a session data key or the legacy account key pair). If decryption yields null for either path, the metadata cannot be read with the available keys, and it throws this error naming the session. Without metadata the session cannot be turned into a resumable one.","triggerScenarios":"decryptWithDataKey or decryptLegacy returns null for session.metadata — wrong key material (dataKey variant key mismatch or legacy secret key from another account), corrupted base64 metadata, or tampered/ciphertext from a different encryption scheme.","commonSituations":"Mixed legacy/new encryption variants after a library upgrade (session encrypted with legacy scheme but resolved with dataKey or vice versa); wrong account logged in; server data partially migrated; corrupted sync storage.","solutions":["Log in with the account that owns the session so the correct decryption key is available.","Ensure both CLI and server are on compatible versions (legacy vs dataKey encryption path) — upgrade the CLI if the session format is newer.","Retry from the original machine where the session was created, if key material is device-bound.","If metadata is corrupt server-side, the session is unrecoverable — start a new session."],"exampleFix":"// before\n$ happy resume <legacy-session-id>   // old CLI resolves with wrong scheme -> metadata decrypt fails\n// after\n$ npm i -g slop@latest && happy auth && happy resume <legacy-session-id>","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const session = await resolveHappySession(id);\n} catch (err) {\n  if ((err as Error).message.startsWith('Failed to decrypt metadata')) {\n    // suggest re-login as owning account / CLI upgrade for newer encryption schemes\n  } else throw err;\n}","preventionTips":["Keep the CLI up to date so legacy vs dataKey encryption variants are handled.","Authenticate as the session-owning account before resuming.","Resume from the original machine when key material is device-bound."],"tags":["encryption","crypto","session-resume"],"backgroundTag":"decryption-failed","analyzedSha":"b824cd0a4681d41af631a8e422a813873e4455b0","analyzedAt":"2026-08-31T23:12:36.205Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}