google-gemini/gemini-cli · warning

MAX_TURNS_EXCEEDED

MAX_TURNS_EXCEEDED

Error message

MAX_TURNS_EXCEEDED

What it means

MAX_TURNS_EXCEEDED here is the local (client-side) enforcement in the legacy agent loop. _runLoop increments turnCount each iteration and, when it exceeds config.getMaxSessionTurns() (and maxTurns>=0), calls _finishStream('max_turns', { code:'MAX_TURNS_EXCEEDED', maxTurns, turnCount }) and returns. This is the producer of the event that [242] translates.

Source

Thrown at packages/core/src/agent/legacy-agent-session.ts:187

    } finally {
      this._clearActiveStream();
    }
  }

  private async _runLoop(
    initialParts: Part[],
    initialDisplayContent?: string,
  ): Promise<void> {
    let currentParts: Part[] = initialParts;
    let currentDisplayContent = initialDisplayContent;
    let turnCount = 0;
    const maxTurns = this._config.getMaxSessionTurns();

    while (true) {
      turnCount++;
      if (maxTurns >= 0 && turnCount > maxTurns) {
        this._finishStream('max_turns', {
          code: 'MAX_TURNS_EXCEEDED',
          maxTurns,
          turnCount: turnCount - 1,
        });
        return;
      }

      const toolCallRequests: ToolCallRequestInfo[] = [];
      let finishedReason: FinishReason | undefined = undefined;
      const responseStream = this._client.sendMessageStream(
        currentParts,
        this._abortController.signal,
        this._promptId,
        undefined,
        currentDisplayContent,
      );
      currentDisplayContent = undefined;

      for await (const event of responseStream) {

View on GitHub (pinned to 5024443c72)

Solutions

  1. Increase config.getMaxSessionTurns() / setMaxSessionTurns().
  2. Set maxTurns to -1 to disable the client-side cap (let server policy govern).
  3. Inspect tool_request/tool_response stream to find why turns accumulate and fix the failing tool.

Example fix

// before
getMaxSessionTurns() { return 20; }
// after
getMaxSessionTurns() { return 100; }
Defensive patterns

Strategy: validation

Validate before calling

const max = config.getMaxSessionTurns();
if (max >= 0 && max < taskEstimatedTurns) config.setMaxSessionTurns(taskEstimatedTurns);

Type guard

function isMaxTurnsFinish(payload: unknown): payload is { code: 'MAX_TURNS_EXCEEDED'; maxTurns: number; turnCount: number } {
  return typeof payload === 'object' && payload !== null && (payload as any).code === 'MAX_TURNS_EXCEEDED';
}

Try / catch

// _finishStream is internal; callers react to the resulting agent_end event:
if (ev.type === 'agent_end' && ev.reason === 'max_turns' && isMaxTurnsFinish(ev.data)) { /* raise budget or refine task */ }

Prevention

When it happens

Trigger: Each while(true) iteration in _runLoop: turnCount++; if (maxTurns>=0 && turnCount>maxTurns) -> _finishStream('max_turns', {...}); return. Triggered when a session runs longer than the configured budget.

Common situations: Default maxTurns is too low for the task; a tool returns errors so the loop never finishes; misconfigured getMaxSessionTurns returning a small number.

Related errors


AI-assisted analysis of google-gemini/gemini-cli@5024443c72 (2026-08-12). Data as JSON: /api/errors/78cfffe987a5b906. Report an issue: GitHub.