Skip to content

Gateway crashes on config reload due to unhandled AbortError #1997

@Wei-EVA

Description

@Wei-EVA

Gateway crashes on config reload due to unhandled AbortError

Description

When configuration is patched via config.patch and the gateway restarts (SIGUSR1), the process frequently crashes with exit code 1 due to an unhandled AbortError.

Environment

  • Clawdbot version: 2026.1.24-0
  • OS: macOS (Apple Silicon)
  • Node: v22.17.1

Steps to Reproduce

  1. Start the gateway normally
  2. Use gateway config.patch to update configuration (e.g., add an API key)
  3. Gateway receives SIGUSR1 and begins restart
  4. Process crashes with exit code 1

Error Log

22:55:13 [reload] config change detected; evaluating reload
22:55:13 [reload] config change requires gateway restart
22:55:13 [gateway] signal SIGUSR1 received
22:55:13 [gateway] received SIGUSR1; restarting
22:55:13 [gmail-watcher] gmail watcher stopped
22:55:13 [clawdbot] Unhandled promise rejection: AbortError: This operation was aborted
    at node:internal/deps/undici/undici:13510:13
    at processTicksAndRejections (node:internal/process/task_queues:105:5)
 ELIFECYCLE  Command failed with exit code 1.

Root Cause Analysis

In src/infra/unhandled-rejections.ts:

process.on("unhandledRejection", (reason, _promise) => {
    if (isUnhandledRejectionHandled(reason)) return;
    console.error("[clawdbot] Unhandled promise rejection:", formatUncaughtError(reason));
    process.exit(1);  // <-- exits immediately
});

During graceful shutdown:

  1. server.close() aborts in-flight network requests
  2. Aborted requests throw AbortError
  3. If not caught, these become unhandledRejection
  4. Process exits with code 1

Suggested Fix

Register a global handler to suppress AbortError during shutdown:

// In src/infra/unhandled-rejections.ts

export function installUnhandledRejectionHandler(): void {
  // Suppress AbortError globally - these are typically intentional cancellations
  registerUnhandledRejectionHandler((reason) => {
    if (reason instanceof Error && reason.name === "AbortError") {
      console.warn("[clawdbot] Suppressed AbortError:", reason.message);
      return true; // handled, don't exit
    }
    return false;
  });

  process.on("unhandledRejection", (reason, _promise) => {
    if (isUnhandledRejectionHandled(reason)) return;
    console.error("[clawdbot] Unhandled promise rejection:", formatUncaughtError(reason));
    process.exit(1);
  });
}

Alternatively, register a temporary handler in gateway-daemon.ts only during the shutdown window.

Workaround

Configure launchd to auto-restart on crash:

<key>KeepAlive</key>
<dict>
  <key>SuccessfulExit</key>
  <false/>
  <key>Crashed</key>
  <true/>
</dict>
<key>ThrottleInterval</key>
<integer>5</integer>

Impact

  • Gateway becomes unavailable until manually restarted
  • Users who are away from their machine lose connectivity to messaging channels
  • Frequent config changes (e.g., during setup) trigger repeated crashes

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions