[Bug] Cancelling retry backoff leaves a referenced timeout alive until the original delay expires
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 76/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- node.js, typescript
- 領域
- backend
調査の方向性
まず packages/agent-core-v2/src/_base/utils/retry.ts を読み、特に sleepForRetry と sleep および abortable の使い方を確認してください。報告には、キャンセル後もタイムアウトが残ることを示す Node.js の再現コードが含まれています。このヘルパーの既存テストを確認し、キャンセルと通常完了のテストを追加してください。キャンセル時に同じ理由で reject され、タイムアウトがクリアされる一方、キャンセルされていない待機は遅延時間の経過後に引き続き完了すれば完了です。
索引モデルが issue の本文から書いたものです。
説明
What version of Kimi Code is running?
Source-level reproduction at current main 44cdf8f4039e2ff20d3fe8a4e7868bd90fd786e1. The affected retry.ts and abort.ts are byte-identical in the latest release tag @moonshot-ai/[email protected] (commit b5e28fd6beac752a2cdcc0ff2f5fdf40e6494fbb). I tested the real source helper, not an installed CLI build.
Which open platform/subscription and model were you using?
Not applicable: offline CPU reproduction, no provider requests or API key.
What platform is your computer?
macOS arm64, Darwin 25.5.0 arm64 arm, Node.js v24.19.0.
What issue are you seeing?
Cancelling sleepForRetry immediately rejects its Promise with the original cancellation reason, but leaves its referenced timeout alive until the original backoff expires. An otherwise idle Node process therefore cannot exit naturally after the caller has already caught the cancellation.
This is not a claim that cancellation fails to reject, that another provider request is sent, or that the complete CLI/TUI is permanently frozen.
What steps can reproduce the bug?
From the repository root at the commit above, run with Node 24.15 or newer. No dependency installation is needed for these two modules:
node --input-type=module <<'JS'
import { sleepForRetry } from './packages/agent-core-v2/src/_base/utils/retry.ts';
const started = performance.now();
const controller = new AbortController();
const reason = new Error('cancel this retry');
const pending = sleepForRetry(650, controller.signal);
controller.abort(reason);
try {
await pending;
} catch (error) {
console.log('original reason:', error === reason);
}
console.log('active resources:', process.getActiveResourcesInfo());
console.log('cancelled after ms:', Math.round(performance.now() - started));
process.once('beforeExit', () => {
console.log('beforeExit after ms:', Math.round(performance.now() - started));
});
JS
Actual output on my machine (non-timer handles can vary):
original reason: true
active resources: [ 'FSReqCallback', 'PipeWrap', 'PipeWrap', 'Timeout' ]
cancelled after ms: 1
beforeExit after ms: 651
What is the expected behavior?
After cancellation, reject promptly with the same reason and clear the pending timeout. With no remaining work, the process should be able to exit without waiting for the cancelled delay. Normal, non-cancelled waits should still complete after their delay.
Additional information
- The helper creates
sleep(delayMs)before racing it withabortable;sleepdiscards the timer handle. Rejecting the outer Promise does not cancel that timer. - Actual callers include full-compaction retries and the opt-in infinite LLM retry path. The issue is the leftover resource, not whether those callers stop retrying.
- In three fresh control runs, cancellation immediately and one event-loop turn after starting 500ms, 32s and 60s sleeps consistently left one active timeout per cancelled wait. Pre-aborted signals created none; normal completion cleared the timer. Long-delay fixtures explicitly cleaned up the observed handles after measurement.
- Independent child processes rejected immediately but stayed alive for about 650ms in all runs. Pre-aborted controls and a test-only control that clears the captured timer on abort exited immediately. Native
node:timers/promisescancellation also left no pending timer. - No repository implementation was changed. No live inference, complete CLI/TUI lifecycle, Windows/Linux, or full-repository test suite was exercised.
- Related reports #1796, #1860 and #2025 concern rate-limit handling/visibility before cancellation. This reproduces after cancellation has already been caught, without HTTP or provider errors.
- #2855 addresses delayed cancellation inside provider SDK retries; rejection here is already immediate. The CLI also has a force-exit fallback from #1233, so I am not claiming that every
kimi -prun hangs. This report is specifically about the engine helper retaining a referenced timer after cancellation.
Contribution
- I am willing to submit a PR for this bug fix myself (please wait for maintainer approval in this issue first)
- 主要言語
- TypeScript
- スター
- 7.9k
- フォーク
- 1.3k
- 平均マージ
- 1日 12時間
- マージ済み PR(30日)
- 103
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
MoonshotAI/kimi-code のほかの issue
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
MoonshotAI/kimi-code#4315 ·
メンテナーはふだん 1 日以内に返信
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 60/100
MoonshotAI/kimi-code#4225 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
MoonshotAI/kimi-code#4177 ·
メンテナーはふだん 1 日以内に返信
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
MoonshotAI/kimi-code#4170 ·
メンテナーはふだん 1 日以内に返信
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
MoonshotAI/kimi-code#4147 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
MoonshotAI/kimi-code の issue をすべて見る
似ている issue
-
area: image-engine bug priority: low
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
snapotter-hq/SnapOtter#3885 ·
メンテナーはふだん 1 日以内に返信
-
Mend: dependency security vulnerability
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
メンテナーはふだん 3 日以内に返信
-
pending triage
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
メンテナーはふだん 1 日以内に返信
-
bug P3 UI/UX
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
メンテナーはふだん 1 日以内に返信
-
clawsweeper:fix-shape-clear clawsweeper:queueable-fix clawsweeper:source-repro impact:ux-friction issue-rating: 🦞 diamond lobster no-stale P3
難易度 2/5 1〜3時間 初心者へのやさしさ 73/100
openclaw/openclaw#182077 · コメント 1 件 · リアクション 1 件 ·
メンテナーはふだん 1 日以内に返信