slopus/happy · error

Happy session lookup authentication expired for legacy accou

Error message

Happy session lookup authentication expired for legacy account credentials.

What it means

fetchSessions lists the account's sessions from the Happy API using legacy account credentials. When the API responds with HTTP 401 (the auth token is expired or rejected), it throws this dedicated error instead of the generic network message, signaling that the stored legacy credentials are no longer valid and the user must re-authenticate.

Source

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

        throw new Error(`Failed to decrypt metadata for Happy session ${session.id}`);
    }

    return parseResumableMetadata(session.id, metadata);
}

async function fetchSessions(credentials: LocalHappyAgentCredentials): Promise<RawSession[]> {
    try {
        const response = await axios.get(`${configuration.serverUrl}/v1/sessions`, {
            headers: {
                Authorization: `Bearer ${credentials.token}`,
                'X-Happy-Client': `cli-coding-session/${configuration.currentCliVersion}`,
            },
        });
        return (response.data as { sessions: RawSession[] }).sessions;
    } catch (error) {
        if (error instanceof AxiosError) {
            if (error.response?.status === 401) {
                throw new Error('Happy session lookup authentication expired for legacy account credentials.');
            }
            throw new Error(`Failed to load Happy sessions: ${error.message}`);
        }
        throw error;
    }
}

export async function resolveHappySession(sessionId: string): Promise<ResumableHappySession> {
    const credentials = readAgentCredentials();
    const sessions = await fetchSessions(credentials);
    const matched = resolveSessionRecordByPrefix(sessions, sessionId);
    return {
        id: matched.id,
        active: matched.active,
        metadata: decryptSessionMetadata(matched, credentials),
    };
}

View on GitHub (pinned to b824cd0a46)

Solutions

  1. Re-authenticate (happy auth / login) to obtain fresh credentials, then retry the resume.
  2. Delete stale local credentials if re-login caches oddly, then log in again.
  3. Check system clock sync (NTP) if tokens expire immediately after refresh.
  4. Verify the account hasn't been deauthorized/rotated server-side.

Example fix

// before
$ happy resume <session-id>   // Happy session lookup authentication expired
// after
$ happy auth                  # refresh legacy credentials
$ happy resume <session-id>
Defensive patterns

Strategy: retry

Try / catch

try {
  const session = await resolveHappySession(id);
} catch (err) {
  if ((err as Error).message.includes('authentication expired')) {
    await runAuthFlow();        // refresh credentials
    return resolveHappySession(id); // single retry after re-auth
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling fetchSessions (via resolveHappySession / happy resume) when the bearer token in the legacy agent credentials has expired or been revoked and the server returns 401.

Common situations: Long-lived machine/credentials not used for weeks; server-side token rotation or session invalidation; password change or account deauthorization on another device; clock skew invalidating JWTs.

Understand the failure class

Related errors


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