Skip to content

Heartbeat duration every >24.85d overflows Node setTimeout, crashes gateway with no auto-respawn #71414

Description

@mayank6136

Summary

Setting agents.defaults.heartbeat.every to a duration greater than ~24.85 days (Node.js's signed-32-bit setTimeout cap of 2,147,483,647 ms) causes the heartbeat scheduler to fire in a tight loop and eventually crashes the gateway with OpenClaw exited with code 1. The container wrapper does not auto-respawn the gateway after exit. The CLI silently falls back to embedded mode on the next invocation.

Reproduction

  1. In openclaw.json, set:
    { "agents": { "defaults": { "heartbeat": { "every": "365d" } } } }
    (or any value that resolves to >2,147,483,647 ms — i.e. anything beyond ~24d 20h)
  2. Restart the gateway and watch container logs.

Observed behaviour

Container logs flood with thousands of lines like:

(node:41) TimeoutOverflowWarning: 23111245866 does not fit into a 32-bit signed integer.
Timeout duration was set to 1.

Eventually the gateway exits:

[22:29:40] WARN: OpenClaw exited with code 1

After this, port 18789 is not listening; subsequent openclaw agent invocations silently fall back to embedded mode (see related issue on silent embedded fallback). docker exec ... ps -ef shows no gateway process; only the proxy node server.mjs remains.

Root cause

Per Node.js docs, setTimeout(fn, delay) clamps delay > 2147483647 to 1 ms. The heartbeat scheduler appears to compute "next fire = now + every" and pass it directly to setTimeout, so the very-large delay gets truncated to 1 ms. The function then runs immediately, recomputes, and re-arms — a tight loop that ultimately exhausts something (event loop / promise queue / heap) and the process dies.

Expected behaviour

At least one of:

  • Reject the config with a clear error during loadConfig if the resolved ms exceeds Node's setTimeout limit.
  • Clamp internally to 2^31-1 ms with a warning.
  • Use a recursive long-timer pattern (re-arm every 24d until the cumulative target is reached).

Additionally, the wrapper / supervisor should auto-respawn the gateway after exit code 1 instead of leaving the proxy alive but the gateway dead.

Workaround

Use a value safely under the cap: "every": "24d" (≈ 2,073,600,000 ms) is safe and still effectively "never" for a "durably disabled" heartbeat.

Environment

OpenClaw 2026.4.12 (1c0672b), running in container ghcr.io/hostinger/hvps-openclaw:latest on Linux/Docker.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions