diff --git a/CHANGELOG.md b/CHANGELOG.md index 30e6a8d5d..4bfbe123f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Browser/Remote CDP ownership checks: skip local-process ownership errors for non-loopback remote CDP profiles when HTTP is reachable but the websocket handshake fails, and surface the remote websocket attach/retry path instead. (#15582) Landed from contributor (#28780) Thanks @stubbi, @bsormagec, @unblockedgamesstudio and @vincentkoc. - Docker/Image health checks: add Dockerfile `HEALTHCHECK` that probes gateway `GET /healthz` so container runtimes can mark unhealthy instances without requiring auth credentials in the probe command. (#11478) Thanks @U-C4N and @vincentkoc. - Daemon/systemd checks in containers: treat missing `systemctl` invocations (including `spawn systemctl ENOENT`/`EACCES`) as unavailable service state during `is-enabled` checks, preventing container flows from failing with `Gateway service check failed` before install/status handling can continue. (#26089) Thanks @sahilsatralkar and @vincentkoc. - Android/Nodes reliability: reject `facing=both` when `deviceId` is set to avoid mislabeled duplicate captures, allow notification `open`/`reply` on non-clearable entries while still gating dismiss, trigger listener rebind before notification actions, and scale invoke-result ack timeout to invoke budget for large clip payloads. (#28260) Thanks @obviyus. diff --git a/src/browser/server-context.ts b/src/browser/server-context.ts index ce7c75a2d..7d405c8bf 100644 --- a/src/browser/server-context.ts +++ b/src/browser/server-context.ts @@ -333,8 +333,9 @@ function createProfileContext( return; } - // HTTP responds but WebSocket fails - port in use by something else - if (!profileState.running) { + // HTTP responds but WebSocket fails - port in use by something else. + // Skip this check for remote CDP profiles since we never own the remote process. + if (!profileState.running && !remoteCdp) { throw new Error( `Port ${profile.cdpPort} is in use for profile "${profile.name}" but not by openclaw. ` + `Run action=reset-profile profile=${profile.name} to kill the process.`, @@ -356,6 +357,14 @@ function createProfileContext( ); } + // At this point profileState.running is always non-null: the !remoteCdp guard + // above throws when running is null, and the remoteCdp path always exits via + // the attachOnly/remoteCdp block. Add an explicit guard for TypeScript. + if (!profileState.running) { + throw new Error( + `Unexpected state for profile "${profile.name}": no running process to restart.`, + ); + } await stopOpenClawChrome(profileState.running); setProfileRunning(null);