slopus/happy · error · Error

Resume session handler not available

Error message

Resume session handler not available

What it means

Thrown by the resume-session RPC handler when this.resumeSessionHandler is unset at the time the RPC arrives, even though a handler was registered. This is a narrow race/lifecycle window: the RPC method is registered but the actual callback has not been attached (or was detached), so the request cannot be fulfilled.

Source

Thrown at packages/happy-cli/src/api/apiMachine.ts:348

            return { message: 'Daemon stop request acknowledged, starting shutdown sequence...' };
        });
    }

    private syncResumeSessionRpcRegistration(): void {
        const method = 'resume-happy-session';

        if (this.resumeSessionHandler) {
            if (!this.rpcHandlerManager.hasHandler(method)) {
                this.rpcHandlerManager.registerHandler(method, async (params: any) => {
                    const { sessionId, model, permissionMode } = params || {};

                    if (!sessionId || typeof sessionId !== 'string') {
                        throw new Error('Session ID is required');
                    }

                    const handler = this.resumeSessionHandler;
                    if (!handler) {
                        throw new Error('Resume session handler not available');
                    }

                    const result = await handler(sessionId, { model, permissionMode });
                    switch (result.type) {
                        case 'success':
                            return { type: 'success', sessionId: result.sessionId };
                        case 'requestToApproveDirectoryCreation':
                            return result;
                        case 'error':
                            throw new Error(result.errorMessage);
                    }
                });
            }
            return;
        }

        if (this.rpcHandlerManager.hasHandler(method)) {
            this.rpcHandlerManager.unregisterHandler(method);

View on GitHub (pinned to b824cd0a46)

Solutions

  1. Wait for the client connection/initialization to complete before calling resume-session
  2. Retry the RPC after a short delay so the handler is attached
  3. Ensure setRPCHandlers/connect assigns resumeSessionHandler before (or atomically with) registering the RPC method

Example fix

// before
await connect();
await rpc.call('session/resume', { sessionId }); // may race
// after
await connect();
await waitFor(client.ready); // handler attached
await rpc.call('session/resume', { sessionId });
Defensive patterns

Strategy: retry

Validate before calling

// Only resume once the client reports readiness
if (!client.ready || !client.resumeSessionHandler) {
  await client.waitForReady();
}

Type guard

function canResume(c: { resumeSessionHandler?: unknown }): c is { resumeSessionHandler: Function } {
  return typeof c.resumeSessionHandler === 'function';
}

Try / catch

try {
  await rpc.call(method, { sessionId });
} catch (e) {
  if (e.message === 'Resume session handler not available') {
    await delay(250);
    return rpc.call(method, { sessionId }); // retry once ready
  } throw e;
}

Prevention

When it happens

Trigger: Invoking the resume-session RPC during client startup before connect()/setRPCHandlers has assigned this.resumeSessionHandler; resuming right after teardown/disconnect cleared the handler.

Common situations: Race between daemon startup and an immediate resume request from the app; reconnect flow where RPC registration runs before handler wiring; tests calling the RPC before full initialization.

Related errors


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