slopus/happy · error
ACP session not started
Error message
ACP session not started
What it means
runGemini communicates with the Gemini CLI via ACP (Agent Client Protocol). A session ID is only assigned after the ACP handshake completes. When the UI update path runs and acpSessionId is still unset, the code throws rather than send a prompt against a non-existent session. This guards against sending user input before the backend is ready.
Source
Thrown at packages/happy-cli/src/gemini/runGemini.ts:1050
// Start session if not started
if (!acpSessionId) {
logger.debug('[gemini] Starting ACP session...');
// Update permission handler with current permission mode before starting session
updatePermissionMode(message.mode.permissionMode);
const { sessionId } = await geminiBackend.startSession();
acpSessionId = sessionId;
logger.debug(`[gemini] ACP session started: ${acpSessionId}`);
wasSessionCreated = true;
currentModeHash = message.hash;
// Model info is already shown in status bar via updateDisplayedModel
logger.debug(`[gemini] Displaying model in UI: ${displayedModel || 'gemini-2.5-pro'}, displayedModel: ${displayedModel}`);
}
}
if (!acpSessionId) {
throw new Error('ACP session not started');
}
// Reset accumulator when sending a new prompt (not when tool calls start)
// Reset accumulated response for new prompt
// This ensures a new assistant message will be created (not updating previous one)
accumulatedResponse = '';
isResponseInProgress = false;
hadToolCallInTurn = false;
taskStartedSent = false; // Reset so new turn can send task_started
// Track if this prompt contains change_title instruction
// If so, don't send task_complete until change_title is completed
pendingChangeTitle = message.message.includes('change_title') ||
message.message.includes('happy__change_title');
changeTitleCompleted = false;
if (!geminiBackend || !acpSessionId) {
throw new Error('Gemini backend or session not initialized');View on GitHub (pinned to b824cd0a46)
Solutions
- Wait for the session-ready signal/UI indicator before typing or sending a prompt
- Check the gemini CLI is installed, on PATH, and starts correctly (run `gemini --version`)
- Restart the session; if it reproduces, enable debug logging to see why the ACP handshake never returned a session ID
Defensive patterns
Strategy: validation
Validate before calling
if (!acpSessionId) {
logger.warn('[gemini] ACP session not ready; skipping prompt');
return;
} Type guard
const hasAcpSession = (id: string | null | undefined): id is string => typeof id === 'string' && id.length > 0;
Try / catch
try {
await sendPromptToAcp(prompt);
} catch (err) {
if (err instanceof Error && err.message === 'ACP session not started') {
await waitForSessionReady();
await sendPromptToAcp(prompt);
} else throw err;
} Prevention
- Gate user input handling on the session-ready event
- Log ACP handshake completion before enabling the input UI
- Surface initialization failures instead of swallowing them
When it happens
Trigger: Inside runGemini, the prompt/display flow is reached while the acpSessionId variable is still null/undefined — i.e. the ACP initialize/newSession handshake has not produced a session ID yet when a prompt arrives.
Common situations: User submits a prompt before the Gemini ACP process finished initializing; the gemini binary fails or is slow to start; an earlier session initialization error was swallowed so acpSessionId never gets set.
Related errors
- Session not started
- ACP session is not started
- Gemini backend or session not initialized
- Backend has been disposed
- Failed to create stdio pipes
AI-assisted analysis of slopus/happy@b824cd0a46 (2026-08-31).
Data as JSON: /api/errors/5bac0c9fa549d193.
Report an issue: GitHub.