MoonshotAI / MoonshotAI/kimi-code

kimi web server process crashes with uncaught AbortError when pausing a goal with a queued continuation

Open
#2,801 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
7.5k
Forks
1.2k
Avg merge
11h 53m
Merged PRs (30d)
350

Description

Version

0.34.0 (native binary, Linux x64)

What happened

While using the web UI served by kimi web, pausing a goal on a session whose goal had a continuation in flight killed the entire server process:

Error [AbortError]: Goal continuation cancelled
    at AgentGoalService.cancelPendingContinuation (...)
    at AgentGoalService.applyLifecycle (...)
    at AgentGoalService.pauseGoal (...)
    at SessionLegacyService.applyAgentConfig (...)
    at SessionLegacyService.updateProfile (...)

Node.js v24.x

The process exits; all other sessions served by the same daemon drop with it. Session data on disk is fine — only the server process dies.

Root cause

Two layers combine:

  1. In packages/agent-core-v2/src/agent/goal/goalService.ts, launchContinuationTurn runs a bookkeeping promise chain (receipt.assigned.then(...).finally(...)) with no catch. When the pending continuation is aborted (pauseGoalapplyLifecyclecancelPendingContinuationreceipt.abort(...)), that chain rejects with an AbortError and becomes an unhandled rejection.
  2. In packages/telemetry/src/crash.ts, the unhandledRejection handler deliberately rethrows when it is the sole listener (print/server modes) to preserve Node's crash-on-rejection behavior — but it rethrows even for AbortError, which it otherwise classifies as expected cancellation noise and skips for tracking.

The same pause in the TUI survives because the TUI registers its own rejection handling; the daemon path has no such boundary.

Minimal reproduction

With the telemetry crash handlers installed and no other unhandledRejection listener (the daemon's shape):

installCrashHandlers();
const abort = new Error('Goal continuation cancelled');
abort.name = 'AbortError';
Promise.reject(abort); // unhandled, like the goal continuation bookkeeping chain

The process exits with throw reason from the rejection handler. With an early return for abort-shaped rejections, the process survives; non-abort rejections still crash as intended.

End-to-end: create a session via the web API, start a goal, let it reach a goal-driven continuation turn, then POST /api/v1/sessions/{id}/profile with {agent_config:{goal_control:pause}} — the daemon exits.

Suggested fix

  • Swallow the rejection in the continuation bookkeeping chain (it only cleans up bookkeeping state; real turn failures already surface via turn.ended events).
  • In the telemetry rejection handler, return early for AbortError instead of rethrowing it.

Happy to send a PR with both changes plus a regression test.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in packages/agent-core-v2/src/agent/goal/goalService.ts at launchContinuationTurn and in packages/telemetry/src/crash.ts at the unhandledRejection handler. Reproduce the pause flow or minimal rejection example, then add regression coverage for AbortError cancellation while preserving crashes for non-abort rejections. Done means pausing a queued continuation no longer exits the daemon.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend, observability
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.