Skip to content

2.87.0 startup crash-loops on hosts with IPv6 disabled on loopback (::1 timeout treated as unclassifiable owner evidence) #7258

Closed

Description

@tizerluo

Client or integration

Other

Area

Service lifecycle

Summary

On hosts where IPv6 is disabled on the loopback interface (net.ipv6.conf.lo.disable_ipv6=1, with all/default also disabled), 2.87.0 refuses to start and crash-loops under systemd.

The new cross-home owner discovery probes both loopback families of every candidate port. On such a host, ::1 is no longer a local address: packets are routed out eth0 toward the IPv6 gateway and dropped, so TCP connects to [::1]:<port> time out instead of being refused. classifyHealthz maps a timeout to "unknown", findCrossHomeOwnerDetailed turns that into an indeterminate verdict, and markCrossHomeSibling refuses startup — even though the IPv4 probe of the same port returned a clean connection refusal ("dead").

Observed on a hub-role deployment whose ~/.codex/config.toml / ~/.grok managed region reference the hub's client-routing port (10102). Note the ordering aspect: the hub binds that port only after the cross-home check, so hub deployments cannot rely on bind order to avoid probing it.

Expected: a loopback family that times out, when the other family of the same port cleanly refuses, should not be fatal owner evidence (or this indeterminate case should warn rather than block startup). Hosts that deliberately disable IPv6 (a common hardening preset, e.g. /etc/sysctl.d/99-disable-ipv6.conf) become permanently unable to start the service after upgrading to 2.87.0.

Reproduction

  1. On Ubuntu, set /etc/sysctl.d/99-disable-ipv6.conf: net.ipv6.conf.all.disable_ipv6=1, net.ipv6.conf.default.disable_ipv6=1, net.ipv6.conf.lo.disable_ipv6=1; reboot or sysctl --system.
  2. Verify the quirk: python3 -c "import socket; s=socket.socket(socket.AF_INET6); s.settimeout(2); s.connect(('::1', 10102))" → TimeoutError (on a healthy host this is an instant ConnectionRefusedError).
  3. Have any cross-home candidate port referenced from client state (e.g. ~/.codex/config.toml with openai_base_url = http://127.0.0.1:10102/v1, or a grok managed block).
  4. npm i -g @bitkyc08/opencodex@2.87.0 and restart the service → immediate exit with the error below; systemd restarts every ~6 s forever.

Fix on our side (service starts immediately): sysctl -w net.ipv6.conf.lo.disable_ipv6=0 and persist. ip -6 route get ::1 changes from via fe80::1 dev eth0 to local ::1 dev lo.

Version

2.87.0

Operating system

Ubuntu (Contabo VPS, x64); the quirk is generic to Linux hosts with IPv6 disabled on lo

Provider and model

n/a — startup path, no provider traffic

Logs or error output

error: Shared-client owner could not be verified (a managed client port answered but its listener could not be classified); refusing startup before any shared-client write. Retry startup after discovery recovers.
      at markCrossHomeSibling (/…/src/cli/cross-home-owner.ts:303:15)

Probe evidence on the affected host:

$ python3 - <<'PY'
import socket
for host, port in (("127.0.0.1", 10102), ("::1", 10102)):
    s = socket.socket(socket.AF_INET6 if ":" in host else socket.AF_INET, socket.SOCK_STREAM); s.settimeout(2)
    try: s.connect((host, port)); print(host, "CONNECTED")
    except Exception as e: print(host, type(e).__name__)
    s.close()
PY
127.0.0.1 ConnectionRefusedError
::1 TimeoutError

$ sysctl net.ipv6.conf.lo.disable_ipv6
net.ipv6.conf.lo.disable_ipv6 = 1

$ ip -6 route get ::1   # before fix
::1 from :: via fe80::1 dev eth0 proto static src fe80::… metric 1024

Screenshots and supporting files

n/a

Redacted configuration

n/a — standard hub deployment; client homes reference the hub loopback port (10102)

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. added
    bugSomething isn't working
    serviceService lifecycle (WinSW/launchd/scheduler)
    on Oct 16, 2026
  2. lidge-jun commented on Oct 17, 2026

    @lidge-jun
    Owner

    Fixed on dev by #7262 (43a3e39): startup now checks whether each loopback address can be bound and skips a family that is unavailable (EADDRNOTAVAIL/EAFNOSUPPORT), so an IPv6-disabled loopback no longer crash-loops. Timeouts on an available family still refuse startup. Ships in 2.88.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingserviceService lifecycle (WinSW/launchd/scheduler)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions