openclaw - 💡(How to fix) Fix Gateway hangs indefinitely on macOS Big Sur: canBindToHost("::1") has no timeout in net.ts

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

On macOS Big Sur, the gateway hangs indefinitely after logging "starting HTTP server..." and never becomes operational. The HTTP port enters LISTEN state but no requests are ever processed.

Error Message

testServer.once("error", () => { On macOS Big Sur (11.x), net.createServer().listen(0, "::1") never fires either the "listening" or "error" event when IPv6 is not properly configured. Since there is no timeout, the Promise never settles, blocking resolveGatewayListenHosts() forever. Add a timeout (e.g. 3 seconds) to canBindToHost so that if neither "listening" nor "error" fires, the function returns false: testServer.once("error", () => {

Root Cause

In src/gateway/net.ts, the canBindToHost() function creates a temporary TCP server to test if a host address is bindable. When called with "::1" (IPv6 loopback) inside resolveGatewayListenHosts(), it uses:

// src/gateway/net.ts (bundled as net-BWcjOlSf.js in v2026.4.11)
async function canBindToHost(host: string): Promise<boolean> {
  return new Promise((resolve) => {
    const testServer = net.createServer();
    testServer.once("error", () => {
      resolve(false);
    });
    testServer.once("listening", () => {
      testServer.close();
      resolve(true);
    });
    testServer.listen(0, host);  // ← no timeout
  });
}

On macOS Big Sur (11.x), net.createServer().listen(0, "::1") never fires either the "listening" or "error" event when IPv6 is not properly configured. Since there is no timeout, the Promise never settles, blocking resolveGatewayListenHosts() forever.

The call chain:

startGatewayServer()
  → log.info("starting HTTP server...")
  → createGatewayRuntimeState()
    → resolveGatewayListenHosts("127.0.0.1")  ← calls canBindToHost("::1")
      → canBindToHost("::1")  ← HANGS INDEFINITELY on Big Sur

Fix Action

Workaround

Set OPENCLAW_DISABLE_IPV6_LISTEN=1 if such an env var is exposed, or configure gateway.bind: "loopback" (which still hits the issue because resolveGatewayListenHosts is called unconditionally for 127.0.0.1).

As a temporary local fix, the bundled net-BWcjOlSf.js (v2026.4.11) / net-D3XSbNNz.js (v2026.4.2) file can be patched directly with the above timeout.

Code Example

// src/gateway/net.ts (bundled as net-BWcjOlSf.js in v2026.4.11)
async function canBindToHost(host: string): Promise<boolean> {
  return new Promise((resolve) => {
    const testServer = net.createServer();
    testServer.once("error", () => {
      resolve(false);
    });
    testServer.once("listening", () => {
      testServer.close();
      resolve(true);
    });
    testServer.listen(0, host);  // ← no timeout
  });
}

---

startGatewayServer()
  → log.info("starting HTTP server...")
createGatewayRuntimeState()
resolveGatewayListenHosts("127.0.0.1")  ← calls canBindToHost("::1")
canBindToHost("::1")HANGS INDEFINITELY on Big Sur

---

// src/gateway/net.ts
async function canBindToHost(host: string): Promise<boolean> {
  return new Promise((resolve) => {
    const testServer = net.createServer();
    const timeout = setTimeout(() => {
      testServer.close();
      resolve(false);
    }, 3000);
    testServer.once("error", () => {
      clearTimeout(timeout);
      resolve(false);
    });
    testServer.once("listening", () => {
      clearTimeout(timeout);
      testServer.close();
      resolve(true);
    });
    testServer.listen(0, host);
  });
}
RAW_BUFFERClick to expand / collapse

Bug Report: Gateway hangs indefinitely on macOS Big Sur (11.x) at "starting HTTP server..."

Version: v2026.4.2 and later
Platform: macOS Big Sur (macOS 11.x)
Node.js: v22.x

Description

On macOS Big Sur, the gateway hangs indefinitely after logging "starting HTTP server..." and never becomes operational. The HTTP port enters LISTEN state but no requests are ever processed.

Root Cause

In src/gateway/net.ts, the canBindToHost() function creates a temporary TCP server to test if a host address is bindable. When called with "::1" (IPv6 loopback) inside resolveGatewayListenHosts(), it uses:

// src/gateway/net.ts (bundled as net-BWcjOlSf.js in v2026.4.11)
async function canBindToHost(host: string): Promise<boolean> {
  return new Promise((resolve) => {
    const testServer = net.createServer();
    testServer.once("error", () => {
      resolve(false);
    });
    testServer.once("listening", () => {
      testServer.close();
      resolve(true);
    });
    testServer.listen(0, host);  // ← no timeout
  });
}

On macOS Big Sur (11.x), net.createServer().listen(0, "::1") never fires either the "listening" or "error" event when IPv6 is not properly configured. Since there is no timeout, the Promise never settles, blocking resolveGatewayListenHosts() forever.

The call chain:

startGatewayServer()
  → log.info("starting HTTP server...")
  → createGatewayRuntimeState()
    → resolveGatewayListenHosts("127.0.0.1")  ← calls canBindToHost("::1")
      → canBindToHost("::1")  ← HANGS INDEFINITELY on Big Sur

Expected Behavior

Gateway should detect that ::1 is unavailable (within a reasonable timeout) and bind to ["127.0.0.1"] only, completing startup normally.

Actual Behavior

Gateway logs "starting HTTP server..." then hangs indefinitely. The TCP port enters LISTEN state but the Node.js event loop is permanently blocked waiting for the canBindToHost("::1") Promise to resolve.

Proposed Fix

Add a timeout (e.g. 3 seconds) to canBindToHost so that if neither "listening" nor "error" fires, the function returns false:

// src/gateway/net.ts
async function canBindToHost(host: string): Promise<boolean> {
  return new Promise((resolve) => {
    const testServer = net.createServer();
    const timeout = setTimeout(() => {
      testServer.close();
      resolve(false);
    }, 3000);
    testServer.once("error", () => {
      clearTimeout(timeout);
      resolve(false);
    });
    testServer.once("listening", () => {
      clearTimeout(timeout);
      testServer.close();
      resolve(true);
    });
    testServer.listen(0, host);
  });
}

Workaround

Set OPENCLAW_DISABLE_IPV6_LISTEN=1 if such an env var is exposed, or configure gateway.bind: "loopback" (which still hits the issue because resolveGatewayListenHosts is called unconditionally for 127.0.0.1).

As a temporary local fix, the bundled net-BWcjOlSf.js (v2026.4.11) / net-D3XSbNNz.js (v2026.4.2) file can be patched directly with the above timeout.

Environment

  • macOS Big Sur 11.6 (Darwin 20.6.0)
  • Node.js v22.22.1
  • network.inet6 (IPv6) may be disabled or not properly configured for loopback

Additional Context

This affects all versions that use resolveGatewayListenHosts to try binding the IPv6 loopback alongside 127.0.0.1. The bug is present in v2026.4.2 (net-D3XSbNNz.js) and v2026.4.11+ (net-BWcjOlSf.js) — the identical canBindToHost implementation ships in both.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING