Skip to content

Crash: unhandled AbortError from void activeSession.abort() on embedded run timeout #5865

@harlantwood

Description

@harlantwood

Bug

The gateway crashes with an unhandled promise rejection when an embedded agent run times out after timeoutMs (default 600s):

02:29:59 [agent/embedded] embedded run timeout: runId=e3beb470-d7e8-4875-b96f-d922db3b0ffb sessionId=1cf5fc39-e717-4d2e-8047-c828f228f515 timeoutMs=600000
02:29:59 [clawdbot] Unhandled promise rejection: AbortError: This operation was aborted
    at node:internal/deps/undici/undici:14902:13
    at processTicksAndRejections (node:internal/process/task_queues:105:5)

The process then exits via process.exit(1) in infra/unhandled-rejections.js:27.

Root Cause

In agents/pi-embedded-runner/run/attempt.js, the abortRun function (line ~472-483) calls:

void activeSession.abort();

When the timeout fires, abortRun(true) is invoked, which:

  1. Calls runAbortController.abort(makeTimeoutAbortReason()) — this correctly propagates through the abortable() wrapper and is caught at line ~658-660.
  2. Calls void activeSession.abort() — this internally cancels in-flight HTTP requests (fetch calls to the AI provider via Node's undici). Those fetch requests reject with AbortError: This operation was aborted. Since the promise from activeSession.abort() is discarded with void, the rejection is unhandled.

The unhandled rejection handler at infra/unhandled-rejections.js:22-28 does not filter AbortErrors, so it crashes the process.

Suggested Fix

Replace:

void activeSession.abort();

With:

activeSession.abort().catch(() => { /* intentional: abort errors during timeout are expected */ });

Alternatively, the registerUnhandledRejectionHandler API could be used to register a handler that suppresses AbortError rejections originating from timeout aborts, but catching at the call site is more precise.

Environment

  • clawdbot 2026.1.24-3 (885167d)
  • Node v22.22.0 (undici built-in fetch)
  • macOS

Steps to Reproduce

  1. Start clawdbot gateway
  2. Trigger an embedded agent run (e.g. via webchat)
  3. Let it run until the timeout fires (600s by default, or configure a shorter timeoutMs)
  4. The process crashes with the AbortError shown above

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions