gemini-cli - ✅(Solved) Fix Timer not cleared on error path in toolDistillationService.generateIntentSummary [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
google-gemini/gemini-cli#25074Fetched 2026-04-10 03:44:49
View on GitHub
Comments
0
Participants
1
Timeline
3
Reactions
0
Participants
Timeline (top)
labeled ×2cross-referenced ×1

Error Message

If generateContent() throws (network error, rate-limit, malformed response), the catch block runs but the 15-second timer is never cleared. The timer fires later, calling controller.abort() on a stale AbortController. The generateContent call here is used for progressive enhancement (distilling large tool outputs). Failures are expected and handled gracefully, which means the error path is a realistic code path not just a theoretical edge case.

Fix Action

Fixed

PR fix notes

PR #25076: fix(core): clear timeout on all exit paths in generateIntentSummary

Description (problem / solution / changelog)

Fixes #25074

What

generateIntentSummary creates a 15-second setTimeout to abort stale summarization requests, but clearTimeout only runs on the success path. If generateContent() throws, the timer is never cleared — it fires 15 seconds later calling abort() on a stale AbortController.

Fix

Hoist AbortController and setTimeout before the try block and move clearTimeout into a finally block, matching the established pattern in fetchWithTimeout (packages/core/src/utils/fetch.ts:207).

Tests

  • Added test verifying clearTimeout is called when generateContent rejects
  • All 71 tests in packages/core/src/context/ pass
  • TypeScript, ESLint, and Prettier pass

Changed files

  • packages/core/src/context/toolDistillationService.test.ts (modified, +22/-0)
  • packages/core/src/context/toolDistillationService.ts (modified, +4/-5)

Code Example

// packages/core/src/context/toolDistillationService.ts line 258-291 (before fix)
try {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), 15000);

  const summaryResponse = await this.geminiClient.generateContent(...);

  clearTimeout(timeoutId);  // only runs on success

  return summaryResponse.candidates?.[0]?.content?.parts?.[0]?.text;
} catch (e) {
  // clearTimeout is never called here
  return undefined;
}
RAW_BUFFERClick to expand / collapse

What happened?

The generateIntentSummary method in ToolOutputDistillationService creates a 15-second setTimeout to abort long-running summarization requests, but clearTimeout is only called on the success path.

// packages/core/src/context/toolDistillationService.ts line 258-291 (before fix)
try {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), 15000);

  const summaryResponse = await this.geminiClient.generateContent(...);

  clearTimeout(timeoutId);  // only runs on success

  return summaryResponse.candidates?.[0]?.content?.parts?.[0]?.text;
} catch (e) {
  // clearTimeout is never called here
  return undefined;
}

If generateContent() throws (network error, rate-limit, malformed response), the catch block runs but the 15-second timer is never cleared. The timer fires later, calling controller.abort() on a stale AbortController.

The generateContent call here is used for progressive enhancement (distilling large tool outputs). Failures are expected and handled gracefully, which means the error path is a realistic code path not just a theoretical edge case.

What did you expect to happen?

clearTimeout should run on every exit path. The codebase already has the correct pattern in fetchWithTimeout (packages/core/src/utils/fetch.ts line 207), which uses try/catch/finally with clearTimeout in the finally block.

Client information

Identified via code review on main branch. The inconsistency is visible in source at packages/core/src/context/toolDistillationService.ts line 281 vs the established pattern in packages/core/src/utils/fetch.ts line 207

Login information

code-level bug, not auth-related

Anything else we need to know?

No response

extent analysis

TL;DR

The clearTimeout call should be moved to a finally block to ensure it runs on every exit path, preventing stale AbortController aborts.

Guidance

  • Move the clearTimeout(timeoutId) call to a finally block to guarantee its execution regardless of the method's outcome.
  • Review similar timeout implementations in the codebase to ensure consistency with the established pattern in fetchWithTimeout.
  • Verify that the finally block is correctly handling the clearTimeout call by testing both success and failure paths.
  • Consider adding a comment or documentation to highlight the importance of clearing timeouts in all exit paths.

Example

try {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), 15000);

  const summaryResponse = await this.geminiClient.generateContent(...);

  return summaryResponse.candidates?.[0]?.content?.parts?.[0]?.text;
} catch (e) {
  return undefined;
} finally {
  clearTimeout(timeoutId);
}

Notes

This fix assumes that the finally block will correctly handle the clearTimeout call. If the codebase has specific requirements or constraints that might affect this, additional review may be necessary.

Recommendation

Apply workaround: Move the clearTimeout call to a finally block to ensure it runs on every exit path, as this directly addresses the identified issue and aligns with the established pattern in fetchWithTimeout.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING