#21459: fix(gateway): resolve port from profile config, not inherited env
gateway
cli
size: M
Cluster:
Gateway and Session Fixes
## Summary
Fixes two bugs that prevent running multiple OpenClaw gateway instances on the same machine using `--profile`.
Closes #17833
## Bug 1 — `OPENCLAW_GATEWAY_PORT` env var leaks between profiles
**Root cause:** `startGatewayServer()` sets `process.env.OPENCLAW_GATEWAY_PORT` so child processes can discover the running port. When a second gateway starts under a different profile, it inherits this env var, causing `resolveGatewayPort()` to return the parent's port before reaching the profile's own config.
**Fix (`src/cli/profile.ts`):** `applyCliProfileEnv` now deletes `OPENCLAW_GATEWAY_PORT` unconditionally before applying profile defaults. This lets `resolveGatewayPort` fall through to the profile's config (or `DEFAULT_GATEWAY_PORT`). The `--port` CLI flag is unaffected because it's passed as a `portOverride` that bypasses `resolveGatewayPort` entirely. For the `dev` profile, the port is then unconditionally set to 19001.
## Bug 2 — `OPENCLAW_PROFILE` env var doesn't derive state/config paths
**Root cause:** `entry.ts` only called `applyCliProfileEnv` when `--profile` was in argv. When the profile was set via `OPENCLAW_PROFILE=morebetter` env var, `applyCliProfileEnv` never ran, so `OPENCLAW_STATE_DIR` and `OPENCLAW_CONFIG_PATH` were never derived, causing everything to fall back to `~/.openclaw/`.
**Fix (`src/entry.ts`):** Compute an `effectiveProfile` from the flag value OR the `OPENCLAW_PROFILE` env var. Only strip `--profile` from argv when it was actually in argv (not env-sourced).
## ⚠️ Behavior Change
The `dev` profile test previously expected `OPENCLAW_GATEWAY_PORT=19099` to be preserved (testing that explicit env values were not overridden). With this fix, `applyCliProfileEnv` now **unconditionally clears** `OPENCLAW_GATEWAY_PORT` before applying profile defaults, so the dev profile port changes from the inherited `19099` to the profile-configured `19001`. This is the correct behavior — the old test was accidentally validating the bug (inherited port winning over profile config).
## Tests
- Updated `src/cli/profile.test.ts`: renamed the "does not override explicit env values" test to clarify that `OPENCLAW_GATEWAY_PORT` is intentionally cleared; added new test for non-dev profile port clearing.
- Added `resolveGatewayPort` unit tests in `src/config/paths.test.ts`: env-over-config, config fallback, `DEFAULT_GATEWAY_PORT`, invalid env values, zero port, and profile-isolation scenario (8 new tests).
- All 635 existing tests pass.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Fixes two critical bugs that prevented running multiple gateway instances with different profiles on the same machine. The changes ensure proper environment variable isolation between profiles by clearing inherited service-scoped env vars (`OPENCLAW_GATEWAY_PORT`, `OPENCLAW_LAUNCHD_LABEL`, `OPENCLAW_SYSTEMD_UNIT`, `OPENCLAW_SERVICE_VERSION`) before applying profile defaults. Also fixes `OPENCLAW_PROFILE` env var handling to derive state/config paths correctly. Additionally makes `gateway start` idempotent to prevent session disruption.
Key changes:
- `applyCliProfileEnv` now unconditionally clears inherited service env vars for profile isolation
- `entry.ts` now computes effectiveProfile from both `--profile` flag and `OPENCLAW_PROFILE` env var
- `runServiceStart` now returns "already-running" instead of restarting when service is loaded
- Comprehensive test coverage added (8 new `resolveGatewayPort` tests, updated profile tests, idempotency test)
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk - fixes critical bugs with comprehensive test coverage
- The implementation is well-tested with 8 new unit tests for `resolveGatewayPort`, updated profile tests validating the new clearing behavior, and an idempotency test for `runServiceStart`. The fixes address real bugs that prevent multi-profile usage and session disruption. The behavior change is intentional and correctly documented in tests. All 635 existing tests pass.
- No files require special attention
<sub>Last reviewed commit: ff76554</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#15981: fix: include --profile in systemd service ExecStart
by MisterGuy420 · 2026-02-14
87.3%
#11455: fix(gateway): default gateway.mode to local when unset
by AnonO6 · 2026-02-07
80.9%
#11159: fix(cli): parse --profile flag after subcommand name
by hclsys · 2026-02-07
80.7%
#23301: Gateway: prevent dev reset from touching default profile state
by tristanmanchester · 2026-02-22
79.5%
#8745: fix(gateway): respect gateway.port config and --port CLI flag
by revenuestack · 2026-02-04
79.3%
#22716: fix: gateway status probe uses wss:// when TLS enabled; accept self...
by Fratua · 2026-02-21
78.9%
#19885: test(gateway,browser): isolate tests from ambient OPENCLAW_GATEWAY_...
by NewdlDewdl · 2026-02-18
78.8%
#11147: fix(daemon): stop gateway by port when no daemon service is active
by jasonthewhale · 2026-02-07
78.5%
#17835: Fix misleading gateway stop hints for standalone listeners
by ConnorCallison · 2026-02-16
77.8%
#9728: fix(gateway): browser.snapshot ignores profile parameter (#9723)
by divol89 · 2026-02-05
77.8%