slopus/happy · error

Ambiguous Happy session "${trimmed}" matches ${matches.lengt

Error message

Ambiguous Happy session "${trimmed}" matches ${matches.length} sessions. Be more specific.

What it means

When the supplied prefix matches more than one session record, resolveSessionRecordByPrefix cannot choose and throws this ambiguity error listing the match count. Prefix-based resolution is only safe when it yields a single record, so the library forces the caller to supply a longer, more specific prefix.

Source

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

    seq: number;
    metadataVersion: number;
    agentStateVersion: number;
    encryptionKey: Uint8Array;
    encryptionVariant: 'legacy' | 'dataKey';
};

export function resolveSessionRecordByPrefix<T extends { id: string }>(records: T[], sessionId: string): T {
    const trimmed = sessionId.trim();
    if (!trimmed) {
        throw new Error('Happy session ID is required: happy resume <session-id>');
    }

    const matches = records.filter((record) => record.id.startsWith(trimmed));
    if (matches.length === 0) {
        throw new Error(`No Happy session found matching "${trimmed}"`);
    }
    if (matches.length > 1) {
        throw new Error(`Ambiguous Happy session "${trimmed}" matches ${matches.length} sessions. Be more specific.`);
    }
    return matches[0];
}

function decryptBoxBundle(bundle: Uint8Array, recipientSecretKey: Uint8Array): Uint8Array | null {
    if (bundle.length < 56) {
        return null;
    }

    const ephemeralPublicKey = bundle.slice(0, 32);
    const nonce = bundle.slice(32, 56);
    const ciphertext = bundle.slice(56);
    const decrypted = tweetnacl.box.open(ciphertext, nonce, ephemeralPublicKey, recipientSecretKey);

    return decrypted ? new Uint8Array(decrypted) : null;
}

function readAgentCredentials() {

View on GitHub (pinned to b824cd0a46)

Solutions

  1. Provide a longer prefix (or the full session ID) so exactly one session matches.
  2. List sessions and pick the exact ID before resuming.
  3. In tooling, add pre-validation: filter records by the prefix yourself and require matches.length === 1 before calling.

Example fix

// before
happy resume a1            // matches 7 sessions
// after
happy resume a1b2c3d4      // longer prefix, unique match
Defensive patterns

Strategy: validation

Validate before calling

const matches = records.filter(r => r.id.startsWith(prefix));
if (matches.length > 1) {
  console.error(`Prefix "${prefix}" is ambiguous (${matches.length} matches). Use a longer prefix.`);
  process.exit(1);
}

Prevention

When it happens

Trigger: Calling resolveSessionRecordByPrefix(records, "a1") when records contains two or more session IDs beginning with "a1" — e.g. short prefixes colliding across sessions created around the same time.

Common situations: Using very short prefixes (1–2 characters) on accounts with many sessions; UUIDs sharing common prefixes (same first hex chars); shell history re-run with a partially remembered ID.

Related errors


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