From 13cdeba7e30b2c1bfb8d9795295025dfde6a9980 Mon Sep 17 00:00:00 2001 From: Alex Cheney Date: Tue, 10 Mar 2026 14:37:24 -0700 Subject: [PATCH] fix(bootstrap): set gateway.mode before onboard to prevent crash loop During bootstrap, `onboard --install-daemon` starts the gateway daemon immediately. The gateway's startup guard requires `gateway.mode=local` but this was only set *after* onboard completed, causing the daemon to block with "Gateway start blocked: set gateway.mode=local" and enter a crash loop. The web UI then fails with "Gateway WebSocket connection failed". Move `ensureGatewayModeLocal()` and `ensureGatewayPort()` to run before the onboard command so the config is in place when the daemon first starts. Co-Authored-By: Claude Opus 4.6 --- src/cli/bootstrap-external.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/cli/bootstrap-external.ts b/src/cli/bootstrap-external.ts index f08f77c3d75..1fc3d35f669 100644 --- a/src/cli/bootstrap-external.ts +++ b/src/cli/bootstrap-external.ts @@ -1709,6 +1709,15 @@ export async function bootstrapCommand( posthogKey: process.env.POSTHOG_KEY || "", }); + // Ensure gateway.mode=local BEFORE onboard so the daemon starts successfully. + // Previously this ran post-onboard, but onboard --install-daemon starts the + // gateway immediately — if gateway.mode is unset at that point the daemon + // blocks with "set gateway.mode=local" and enters a crash loop. + await ensureGatewayModeLocal(openclawCommand, profile); + // Persist the assigned port so the daemon binds to the correct port on first + // start rather than falling back to the default. + await ensureGatewayPort(openclawCommand, profile, gatewayPort); + const onboardArgv = [ "--profile", profile, @@ -1752,13 +1761,8 @@ export async function bootstrapCommand( const postOnboardSpinner = !opts.json ? spinner() : null; postOnboardSpinner?.start("Finalizing configuration…"); - // Ensure gateway.mode=local so the gateway never drifts to remote mode. - // Keep this post-onboard so we normalize any wizard defaults. - await ensureGatewayModeLocal(openclawCommand, profile); - postOnboardSpinner?.message("Configuring gateway port…"); - // Persist the assigned port so all runtime clients (including web) resolve - // the same gateway target on subsequent requests. - await ensureGatewayPort(openclawCommand, profile, gatewayPort); + // gateway.mode and gateway.port are now set pre-onboard (before + // --install-daemon) so the daemon can start without blocking. See above. postOnboardSpinner?.message("Setting tools profile…"); // DenchClaw requires the full tool profile; onboarding defaults can drift to // messaging-only, so enforce this on every bootstrap run.