{"record":{"id":"b41a52331d1581be","repo":"google-gemini/gemini-cli","slug":"not-currently-generating","errorCode":null,"errorMessage":"Not currently generating","messagePattern":"Not currently generating","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/cli/src/acp/acpSession.ts","lineNumber":200,"sourceCode":"        content: {\n          type: 'text',\n          text: `[MODE_UPDATE] ${payload.mode}`,\n        },\n      });\n    }\n  };\n\n  dispose(): void {\n    coreEvents.off(\n      CoreEvent.ApprovalModeChanged,\n      this.handleApprovalModeChanged,\n    );\n    this.disposeController.abort();\n  }\n\n  async cancelPendingPrompt(): Promise<void> {\n    if (!this.pendingPrompt) {\n      throw new Error('Not currently generating');\n    }\n\n    this.pendingPrompt.abort();\n    this.pendingPrompt = null;\n  }\n\n  setMode(modeId: acp.SessionModeId): acp.SetSessionModeResponse {\n    const availableModes = buildAvailableModes(\n      this.context.config.isPlanEnabled(),\n    );\n    const mode = availableModes.find((m) => m.id === modeId);\n    if (!mode) {\n      throw new Error(`Invalid or unavailable mode: ${modeId}`);\n    }\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n    this.context.config.setApprovalMode(mode.id as ApprovalMode);\n    return {};\n  }","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/5024443c7217464a66e98f80d73172a26440bd8f/packages/cli/src/acp/acpSession.ts#L182-L218","documentation":"cancelPendingPrompt() aborts the in-flight prompt via its AbortController. If this.pendingPrompt is null — meaning no prompt() call is currently active — the method throws to signal that the cancel is a no-op. The Session tracks at most one active prompt at a time.","triggerScenarios":"An ACP client sends a cancel notification (e.g., cancelCurrentRequest) when the session is idle. This happens with duplicate cancels, cancel-after-completion, or client/server state desynchronization.","commonSituations":"Client-side race condition where the prompt already completed before the cancel arrived; double-cancel from the client; client state desync after an error; automated test harness sending cancel unconditionally.","solutions":["On the client side, track whether a prompt is active before sending a cancel notification.","Wrap cancelPendingPrompt() in a try-catch and treat the 'Not currently generating' error as benign.","Make cancel idempotent by checking this.pendingPrompt before calling."],"exampleFix":"// before\nawait session.cancelPendingPrompt(); // throws when idle\n\n// after\ntry {\n  await session.cancelPendingPrompt();\n} catch (e) {\n  if (e instanceof Error && e.message === 'Not currently generating') {\n    // No-op: nothing to cancel\n  } else {\n    throw e;\n  }\n}","handlingStrategy":"try-catch","validationCode":"// Track prompt state on the caller/client side\nlet promptActive = false;\n\nasync function safePrompt(session: Session, params: acp.PromptRequest) {\n  promptActive = true;\n  try {\n    return await session.prompt(params);\n  } finally {\n    promptActive = false;\n  }\n}\n\nasync function safeCancel(session: Session) {\n  if (promptActive) {\n    await session.cancelPendingPrompt();\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await session.cancelPendingPrompt();\n} catch (e) {\n  if (e instanceof Error && e.message === 'Not currently generating') {\n    // Benign: nothing to cancel, ignore\n    return;\n  }\n  throw e;\n}","preventionTips":["Track whether a prompt is active on the client side before sending cancel.","Treat cancel as idempotent — never assume a prompt is still in flight.","Handle the 'Not currently generating' error gracefully in automated test harnesses."],"tags":["acp","session","cancel","state"],"backgroundTag":null,"analyzedSha":"5024443c7217464a66e98f80d73172a26440bd8f","analyzedAt":"2026-08-12T06:01:53.711Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}