Skip to content

[Bug]: openclaw node install does not include OPENCLAW_GATEWAY_TOKEN in LaunchAgent plist EnvironmentVariables #31041

@OneStepAt4time

Description

@OneStepAt4time

Summary

openclaw node install generates a LaunchAgent plist that does not include OPENCLAW_GATEWAY_TOKEN in the EnvironmentVariables section, even when the env var is set during installation. This causes the node service to fail with gateway token mismatch on every restart/reboot, since the runner code falls back to reading gateway.auth.token from openclaw.json — which may not match the remote gateway's token in a multi-machine setup.

Context

This affects the documented architecture where:

  • Machine A (e.g., Docker container on a server) runs the gateway
  • Machine B (e.g., a Mac) runs as a headless node connected to the remote gateway via Tailscale/TLS

The node host authenticates to the gateway using OPENCLAW_GATEWAY_TOKEN. When running openclaw node run manually with the env var, everything works. But openclaw node install doesn't persist this env var into the service definition.

Steps to reproduce

  1. On Machine B (node), set the gateway token and install:

    OPENCLAW_GATEWAY_TOKEN="<remote-gateway-token>" openclaw node install \
      --host gateway.example.ts.net --port 443 --tls --display-name "Mac"
  2. Check the generated plist:

    grep "GATEWAY_TOKEN" ~/Library/LaunchAgents/ai.openclaw.node.plist

    Result: No output — OPENCLAW_GATEWAY_TOKEN is not present.

  3. Start the service:

    launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/ai.openclaw.node.plist
  4. Check logs:

    cat ~/.openclaw/logs/node.err.log | tail -5

    Result:

    node host gateway connect failed: unauthorized: gateway token mismatch (provide gateway auth token)
    gateway connect failed: Error: unauthorized: gateway token mismatch (provide gateway auth token)
    node host gateway closed (1008): unauthorized: gateway token mismatch (provide gateway auth token)
    

Expected behavior

openclaw node install should include OPENCLAW_GATEWAY_TOKEN in the plist's EnvironmentVariables when:

  • The env var is set during node install, OR
  • A --token flag is provided to node install, OR
  • The token is read from node.json (via a new gatewayToken field)

Actual behavior

The generated plist contains many OPENCLAW_* env vars (service markers, labels, etc.) but not OPENCLAW_GATEWAY_TOKEN. The node service starts, cannot authenticate to the remote gateway, and enters a reconnect loop.

Root cause

In src/node-host/runner.ts, the token is correctly resolved at runtime:

const token =
    process.env.OPENCLAW_GATEWAY_TOKEN?.trim() ||
    (isRemoteMode ? cfg.gateway?.remote?.token : cfg.gateway?.auth?.token);

But the service installer that generates the plist/systemd unit does not capture OPENCLAW_GATEWAY_TOKEN from the current environment into the service definition.

The fallback path (gateway.auth.token from openclaw.json) doesn't help because:

  • On a node-only machine, openclaw.json may have a different token (from a previous local gateway setup)
  • Or openclaw.json may not have a gateway.auth.token at all
  • The node.json schema (NodeHostConfig) has no field for the gateway token

Workaround

Manually patch the plist after installation:

# After openclaw node install:
sed -i '' 's|<key>OPENCLAW_SERVICE_KIND</key>|<key>OPENCLAW_GATEWAY_TOKEN</key>\
    <string>YOUR_TOKEN_HERE</string>\
    <key>OPENCLAW_SERVICE_KIND</key>|' ~/Library/LaunchAgents/ai.openclaw.node.plist

Then reload:

launchctl bootout gui/$(id -u)/ai.openclaw.node 2>/dev/null
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/ai.openclaw.node.plist

This workaround is fragile — any subsequent openclaw node install --force will overwrite the plist and remove the token again.

Suggested fix

Any of these would work:

  1. Capture OPENCLAW_GATEWAY_TOKEN from env during install — If the env var is set when node install runs, include it in the generated plist/systemd unit EnvironmentVariables.

  2. Add --token flag to node install — Similar to how gateway install handles --token. Example:

    openclaw node install --host gw.example.net --port 443 --tls --token "<token>"
  3. Add gatewayToken to node.json — Extend NodeHostConfig schema to include a gatewayToken field, and have the runner read it as a fallback.

Option 2 is the cleanest UX and consistent with gateway install.

Related issues

Environment

  • OpenClaw version: 2026.2.26 (node) / 2026.2.27 (gateway)
  • OS: macOS 26.x (arm64) — node; Linux WSL2 Docker — gateway
  • Install method: npm global (node), Docker (gateway)
  • Connection: Tailscale Serve (wss:// via .ts.net domain)
  • Node type: headless (openclaw node run / openclaw node install)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions