slopus/happy · error

Failed to decrypt data key for Happy session ${session.id}

Error message

Failed to decrypt data key for Happy session ${session.id}

What it means

resolveSessionEncryption decrypts the session's base64 dataEncryptionKey using the account's content key pair (secretKey) via a NaCl box bundle. If decryptBoxBundle returns null — decryption failed because this account's secret key cannot open the bundle — it throws this error naming the session. It means the session's data key is not recoverable with the current credentials.

Source

Thrown at packages/happy-cli/src/resume/resolveHappySession.ts:104

}

function readAgentCredentials() {
    const credentialPath = getLocalHappyAgentCredentialPath();
    const credentials = readLocalHappyAgentCredentials();
    if (!credentials) {
        throw new Error(
            `Cannot resume historical Happy sessions through legacy account credentials because ${credentialPath} is missing.`,
        );
    }
    return credentials;
}

function resolveSessionEncryption(session: RawSession, credentials: LocalHappyAgentCredentials): RecordEncryption {
    if (session.dataEncryptionKey) {
        const encrypted = decodeBase64(session.dataEncryptionKey);
        const sessionKey = decryptBoxBundle(encrypted.slice(1), credentials.contentKeyPair.secretKey);
        if (!sessionKey) {
            throw new Error(`Failed to decrypt data key for Happy session ${session.id}`);
        }
        return {
            key: sessionKey,
            variant: 'dataKey',
        };
    }

    return {
        key: credentials.secret,
        variant: 'legacy',
    };
}

function decryptSessionMetadata(session: RawSession, credentials: LocalHappyAgentCredentials): Metadata {
    const encryption = resolveSessionEncryption(session, credentials);
    const encryptedMetadata = decodeBase64(session.metadata);
    const metadata = encryption.variant === 'dataKey'
        ? decryptWithDataKey(encryptedMetadata, encryption.key)

View on GitHub (pinned to b824cd0a46)

Solutions

  1. Verify you are authenticated as the account that created/owns the session; re-login with the correct account.
  2. Confirm the credentials content key pair matches the one used at session creation (don't mix accounts across machines).
  3. If the key was rotated or the session was created under an old account, resume from the original machine or export/import the correct key pair.
  4. If the bundle is corrupt, start a new session — the data key is unrecoverable.

Example fix

// before
$ happy auth --account work    # wrong account
$ happy resume <session-id>    // Failed to decrypt data key
// after
$ happy auth --account personal  # owning account
$ happy resume <session-id>
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify identity before resuming:
const creds = readLocalHappyAgentCredentials();
if (creds.accountId !== expectedOwnerAccountId) {
  console.error('Logged in with the wrong account for this session');
}

Try / catch

try {
  await resolveHappySession(id);
} catch (err) {
  if ((err as Error).message.startsWith('Failed to decrypt data key')) {
    // surface 'wrong account / unrecoverable key' to the user; prompt re-login as owning account
  } else throw err;
}

Prevention

When it happens

Trigger: Calling resolveSessionEncryption for a session whose dataEncryptionKey was encrypted to a different account's public key; corrupted or truncated key bundle; credentials from a different happy account than the session owner; base64 payload malformed.

Common situations: Logged in with the wrong account; team/shared sessions where the key was rotated; machine restored from backup with stale credentials; server-side data corrupted or partially migrated.

Related errors


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