MoonshotAI / MoonshotAI/kimi-code
kimi web server process crashes with uncaught AbortError when pausing a goal with a queued continuation
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:
- In
packages/agent-core-v2/src/agent/goal/goalService.ts,launchContinuationTurnruns a bookkeeping promise chain (receipt.assigned.then(...).finally(...)) with nocatch. When the pending continuation is aborted (pauseGoal→applyLifecycle→cancelPendingContinuation→receipt.abort(...)), that chain rejects with anAbortErrorand becomes an unhandled rejection. - In
packages/telemetry/src/crash.ts, theunhandledRejectionhandler deliberately rethrows when it is the sole listener (print/server modes) to preserve Node's crash-on-rejection behavior — but it rethrows even forAbortError, 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.endedevents). - In the telemetry rejection handler, return early for
AbortErrorinstead of rethrowing it.
Happy to send a PR with both changes plus a regression test.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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