slopus/happy · error · LocalResumeSessionError
ambiguous|not_found
ambiguous|not_found
Error message
${message}. Only sessions stored in ${configuration.sessionsFile} can be resumed without legacy account credentials. What it means
When resolveSessionRecordByPrefix throws (session not found by ID/prefix, or the prefix is ambiguous across multiple records), resolveLocalReconnectableSession re-wraps it as LocalResumeSessionError with code 'ambiguous' or 'not_found' and appends a note that only sessions in configuration.sessionsFile are resumable without legacy account credentials.
Source
Thrown at packages/happy-cli/src/resume/localResumeStore.ts:93
export async function resolveLocalReconnectableSession(sessionId: string): Promise<ReconnectableHappySession> {
const records = Object.entries(readPersistedSessions()).map(([id, session]) => ({
id,
...session,
}));
if (records.length === 0) {
throw new LocalResumeSessionError(
`Cannot resume Happy session "${sessionId}" on this machine: no local session encryption data found at ${configuration.sessionsFile}. Start a new Happy session on this machine to enable future resumes.`,
'not_found',
);
}
let matched: PersistedSessionRecord;
try {
matched = resolveSessionRecordByPrefix(records, sessionId);
} catch (error) {
const message = error instanceof Error ? error.message : `No Happy session found matching "${sessionId}"`;
throw new LocalResumeSessionError(
`${message}. Only sessions stored in ${configuration.sessionsFile} can be resumed without legacy account credentials.`,
message.startsWith('Ambiguous') ? 'ambiguous' : 'not_found',
);
}
const encryptionKey = decodeBase64(matched.encryptionKey);
let metadata = parseResumableMetadata(matched.id, matched.metadata);
if (needsFreshMetadata(metadata)) {
metadata = await fetchServerMetadata(matched.id, encryptionKey, matched.encryptionVariant) ?? metadata;
}
return {
id: matched.id,
active: false,
metadata,
seq: matched.seq,
metadataVersion: matched.metadataVersion,
agentStateVersion: matched.agentStateVersion,View on GitHub (pinned to b824cd0a46)
Solutions
- Re-run with a longer, exact session ID to disambiguate a prefix collision
- Run `happy sessions` (or list persisted sessions) to copy the correct full ID
- Verify the session was started on this machine and stored in configuration.sessionsFile; otherwise start/seed locally
- Authenticate with legacy account credentials if the session predates local-only resume support
Example fix
// before happy resume ab // Ambiguous: matches abc123, abcd // after happy resume abc123
Defensive patterns
Strategy: validation
Validate before calling
const records = readPersistedSessions();
const matches = Object.keys(records).filter(id => id === sessionId || id.startsWith(sessionId));
if (matches.length === 0) {
console.error(`No local session matching "${sessionId}"; run happy sessions to list IDs.`);
process.exit(1);
}
if (matches.length > 1) {
console.error(`Ambiguous prefix "${sessionId}" matches: ${matches.join(', ')}`);
process.exit(1);
} Try / catch
try {
await handleResumeCommand([sessionId]);
} catch (e) {
if (e instanceof LocalResumeSessionError && (e.code === 'ambiguous' || e.code === 'not_found')) {
console.error(e.message);
process.exit(1);
}
throw e;
} Prevention
- Use the full session ID instead of a short prefix
- List persisted sessions to copy exact IDs before resuming
- Ensure sessions were started on this machine and stored in sessionsFile
- Use legacy account credentials only for pre-local-store sessions
When it happens
Trigger: Running `happy resume <id>` where the ID/prefix matches no record, or matches multiple records in the sessions file (resolveSessionRecordByPrefix raises 'Ambiguous...'), or the session exists server-side but was never persisted in the local sessions file.
Common situations: Typo'd or stale session ID; resuming a session created under a legacy account on another machine; a prefix that matches several sessions (e.g. 'abc' matching 'abc123' and 'abcd'); sessions file not synced to this machine.
Related errors
- not_found
- Failed to resume Codex thread ${opts.threadId}: ${reason}
- Happy session ID is required: happy resume <session-id>
- Unexpected arguments for happy resume: ${args.slice(1).join(
- Happy session ${session.id} is missing its Codex thread ID.
AI-assisted analysis of slopus/happy@b824cd0a46 (2026-08-31).
Data as JSON: /api/errors/e0f7c4a08c7a965f.
Report an issue: GitHub.