Summary
openclaw update regenerates the LaunchAgent plist (~/Library/LaunchAgents/ai.openclaw.gateway.plist) from scratch, wiping out any custom EnvironmentVariables entries. There's no config path to persist custom env vars across updates.
This is a problem because Node.js 22+ requires workarounds for broken IPv6 dual-stack behavior on networks where IPv6 is unreachable. Without the workaround, the gateway's Telegram channel (and likely any outbound HTTPS to hosts with AAAA records) fails with "Network request for '...' failed!" / ETIMEDOUT.
Environment
- OpenClaw: 2026.2.19-2 (stable, npm)
- Node.js: v24.4.0
- macOS: 26.2 (arm64)
- Gateway: LaunchAgent (
ai.openclaw.gateway)
Steps to reproduce
- Have a network where IPv6 is not fully routable (common on residential networks)
- Add
NODE_OPTIONS to the gateway plist:
<key>NODE_OPTIONS</key>
<string>--dns-result-order=ipv4first --no-network-family-autoselection</string>
- Verify Telegram works:
openclaw health → Telegram: ok
- Run
openclaw update (even if already on the latest version)
openclaw health → Telegram: failed (unknown) - fetch failed
Root cause
Node.js 22+ enables autoSelectFamily by default, which tries IPv6 and IPv4 connections simultaneously. When IPv6 is unreachable (EHOSTUNREACH), the fallback to IPv4 is broken — the IPv4 attempt also times out (ETIMEDOUT), even though direct IPv4 TCP connections succeed.
Evidence:
curl https://api.telegram.org/bot.../getMe → works (system networking handles fallback correctly)
node -e "fetch('https://api.telegram.org/...')" → ETIMEDOUT (both IPv4 and IPv6 fail)
node -e "net.connect(443, '149.154.166.110', ...)" → works (raw TCP to IPv4 is fine)
NODE_OPTIONS="--dns-result-order=ipv4first --no-network-family-autoselection" node -e "fetch(...)" → works
Suggested fix
One or more of:
- Persist custom env vars: Support a config path like
gateway.launchAgent.env (or gateway.nodeOptions) that gets merged into the plist on update/regeneration.
- Detect and apply the workaround automatically: If the gateway detects
ETIMEDOUT on Telegram/outbound HTTPS and IPv6 is unreachable, log a hint or auto-set --no-network-family-autoselection.
- Set
--no-network-family-autoselection by default: Since autoSelectFamily is known to be problematic on many networks, the gateway could default to disabling it in the generated plist.
Current workaround
Manually patch the plist after each update:
# Add to EnvironmentVariables in ~/Library/LaunchAgents/ai.openclaw.gateway.plist:
<key>NODE_OPTIONS</key>
<string>--dns-result-order=ipv4first --no-network-family-autoselection</string>
# Then restart:
openclaw gateway restart
Summary
openclaw updateregenerates the LaunchAgent plist (~/Library/LaunchAgents/ai.openclaw.gateway.plist) from scratch, wiping out any customEnvironmentVariablesentries. There's no config path to persist custom env vars across updates.This is a problem because Node.js 22+ requires workarounds for broken IPv6 dual-stack behavior on networks where IPv6 is unreachable. Without the workaround, the gateway's Telegram channel (and likely any outbound HTTPS to hosts with AAAA records) fails with "Network request for '...' failed!" /
ETIMEDOUT.Environment
ai.openclaw.gateway)Steps to reproduce
NODE_OPTIONSto the gateway plist:openclaw health→Telegram: okopenclaw update(even if already on the latest version)openclaw health→Telegram: failed (unknown) - fetch failedRoot cause
Node.js 22+ enables
autoSelectFamilyby default, which tries IPv6 and IPv4 connections simultaneously. When IPv6 is unreachable (EHOSTUNREACH), the fallback to IPv4 is broken — the IPv4 attempt also times out (ETIMEDOUT), even though direct IPv4 TCP connections succeed.Evidence:
curl https://api.telegram.org/bot.../getMe→ works (system networking handles fallback correctly)node -e "fetch('https://api.telegram.org/...')"→ETIMEDOUT(both IPv4 and IPv6 fail)node -e "net.connect(443, '149.154.166.110', ...)"→ works (raw TCP to IPv4 is fine)NODE_OPTIONS="--dns-result-order=ipv4first --no-network-family-autoselection" node -e "fetch(...)"→ worksSuggested fix
One or more of:
gateway.launchAgent.env(orgateway.nodeOptions) that gets merged into the plist on update/regeneration.ETIMEDOUTon Telegram/outbound HTTPS and IPv6 is unreachable, log a hint or auto-set--no-network-family-autoselection.--no-network-family-autoselectionby default: SinceautoSelectFamilyis known to be problematic on many networks, the gateway could default to disabling it in the generated plist.Current workaround
Manually patch the plist after each update: