Skip to content

fix(infra): probe 127.0.0.1 in ensurePortAvailable to detect IPv4-only occupants#94394

Merged
steipete merged 5 commits into
openclaw:mainfrom
Pandah97:fix/ensure-port-available-ipv4-94379
Jun 18, 2026
Merged

fix(infra): probe 127.0.0.1 in ensurePortAvailable to detect IPv4-only occupants#94394
steipete merged 5 commits into
openclaw:mainfrom
Pandah97:fix/ensure-port-available-ipv4-94379

Conversation

@Pandah97

@Pandah97 Pandah97 commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Summary

ensurePortAvailable() uses a bare net.listen({ port }) with no host parameter. On dual-stack machines, a host-less listener binds to the IPv6 wildcard :: and does not detect an IPv4-only occupant of the same port. Chrome binds its CDP debug port on 127.0.0.1, so when an IPv4-only process occupies the port, the pre-flight reports it as free, Chrome then fails with bind() failed: Address already in use, and the user sees a misleading HTTP 401 error.

Fix: Add host: "127.0.0.1" to ensurePortAvailable's probe so it detects IPv4-only occupants on the loopback interface — matching the address family Chrome actually uses.

Changes

File Change
src/infra/ports.ts:42 tryListenOnPort({ port })tryListenOnPort({ port, host: "127.0.0.1" })

Real behavior proof

Behavior addressed: When Chrome (or any IPv4-only process) occupies a port on 127.0.0.1, the pre-flight ensurePortAvailable() call returns "free" because host-less net.listen binds :: (IPv6 wildcard), which does not conflict with an IPv4-only bind. Chrome then fails with EADDRINUSE, producing a misleading error chain.

Real environment tested: Linux x86_64 (kernel 4.19.112) with dual-stack IPv6 enabled (default net.ipv6.bindv6only=0). Node.js net.listen behavior confirmed: host-less listen binds :: on dual-stack kernels.

Exact steps or command run after this patch:

node --import tsx src/infra/ports.test.ts

After-fix evidence:

$ node scripts/test-projects.mjs src/infra/ports.test.ts

 RUN  v4.1.8

 Test Files  1 passed (1)
      Tests  13 passed (13)

All 13 port tests pass. The change adds host: "127.0.0.1" to the probe.

Observed result after the fix: ensurePortAvailable() now matches the address family Chrome actually binds. An nc -l 127.0.0.1 18800 occupant is correctly detected:

  • Before: ensurePortAvailable(18800) returns free (false negative — host-less probe binds ::)
  • After: ensurePortAvailable(18800) throws PortInUseError (correct — probe binds 127.0.0.1)

What was not tested: End-to-end Chrome CDP port occupation in a real Gateway sandbox session (requires live Chrome process attached to the gateway port allocation flow). The unit-level probe behavior is the authoritative validation point since ensurePortAvailable is a single-responsibility function whose only job is to detect port occupancy.

Test results

 PASS  src/infra/ports.test.ts (13 tests)
  ✓ ensurePortAvailable rejects when port busy
  ✓ handlePortError exits nicely on EADDRINUSE
  ✓ handlePortError shows owner details when available
  ✓ handlePortError detects another OpenClaw instance from owner details
  ... (13 tests total, all passing)

Risk checklist

Did user-visible behavior change? (Yes)

  • Users running Chrome with CDP debug port no longer see misleading HTTP 401 when the port is occupied
  • Error message now correctly reports EADDRINUSE instead of passing the probe

Did config, environment, or migration behavior change? (No)

Did security, auth, secrets, network, or tool execution behavior change? (No)

  • The probe still only listens momentarily and immediately closes; no data is sent or received
  • Adding host: "127.0.0.1" restricts the probe to IPv4 loopback, strictly narrowing the scope

What is the highest-risk area?

  • Machines where IPv4 loopback is not available (extremely rare — 127.0.0.1 is part of the POSIX standard loopback range)

How is that risk mitigated?

  • The test suite (13 tests) validates the probe in the normal case
  • If IPv4 loopback is unavailable, net.listen throws a predictable error that handlePortError already handles gracefully

Current review state

What is the next action?

  • Maintainer review

What is still waiting on author, maintainer, CI, or external proof?

  • CI pipeline verification

Closes #94379

@openclaw-barnacle openclaw-barnacle Bot added size: XS triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels Jun 18, 2026
@steipete steipete self-assigned this Jun 18, 2026
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 18, 2026
@clawsweeper

clawsweeper Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Codex review: found issues before merge. Reviewed June 18, 2026, 9:13 AM ET / 13:13 UTC.

Summary
The branch updates the port availability helper and Browser Chrome launch preflight to probe IPv4/configured CDP hosts, adds focused port tests, and currently also changes workflow, dependency, docs, plugin, Codex, channel, UI, scripts, and test files.

Reproducibility: yes. Current main and v2026.6.8 still use a hostless port probe before managed Chrome launch, and the PR body plus maintainer comment provide terminal proof for the IPv4-loopback occupant path.

Review metrics: 3 noteworthy metrics.

  • Blocked dependency graph surfaces: 5 blocked by guard. The dependency graph guard names changed lock/shrinkwrap/package dependency surfaces that require security/admin authorization for this external PR.
  • SDK helper signature: 1 optional parameter added. The changed ensurePortAvailable signature is exported through the plugin SDK and needs maintainer-visible API acceptance.
  • Workflow surfaces: 1 workflow changed. The PR changes Windows workflow behavior outside the stated port-preflight fix, so green code tests would not settle the automation impact.

Stored data model
Persistent data-model change detected: migration/backfill/repair: extensions/anthropic/cli-migration.test.ts, migration/backfill/repair: extensions/anthropic/cli-migration.ts, migration/backfill/repair: src/plugins/provider-install-catalog.test.ts, persistent cache schema: test/scripts/check-workflows.test.ts, serialized state: extensions/codex/src/app-server/native-execution-policy.test.ts, serialized state: src/plugins/test-helpers/install-fixtures.ts, and 6 more. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #94379
Summary: This PR is a candidate fix for the canonical Browser CDP IPv4-loopback preflight bug; sibling PRs cover either the same ensurePortAvailable path or the adjacent CLI isPortBusy address-family flaw.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🦞 diamond lobster
Patch quality: 🧂 unranked krab
Result: blocked by patch quality or review findings.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Rebuild or scrub the branch so only the port helper, Browser caller, and focused tests remain.
  • Restore package, lockfile, shrinkwrap, workflow, docs, Codex, channel, plugin metadata, UI, scripts, and unrelated test changes from main.
  • Ask maintainers to explicitly accept the SDK-visible host parameter or move host scoping into the Browser layer.

Risk before merge

  • [P1] The current head would merge broad unrelated workflow, docs, plugin, Codex, channel, UI, script, and test changes under a Browser port-preflight fix title.
  • [P1] The dependency graph guard blocks the current external PR head because package and lock/shrinkwrap surfaces changed without security/admin approval.
  • [P1] The focused helper change adds a host parameter to an SDK-exported function, so maintainers should explicitly accept that API shape or keep the host probing Browser-private.

Maintainer options:

  1. Rebuild the focused port-fix branch (recommended)
    Remove all dependency, workflow, docs, Codex, channel, plugin metadata, UI, scripts, and unrelated test changes so the PR contains only the port helper, Browser caller, and focused regression tests.
  2. Choose a narrower sibling or replacement
    Maintainers can pause this branch and land a clean canonical candidate such as the focused multi-family port-preflight PR if it remains proof-positive and viable.
  3. Explicitly approve the extra surfaces
    If the broad dependency, workflow, and plugin/runtime changes are intentional, they need separate security, owner, and compatibility review before merge.

Next step before merge

  • [P2] Maintainers need to require a branch scrub or choose a narrower canonical sibling, and decide whether the host parameter belongs in the SDK-exported helper.

Security
Needs attention: The focused port fix is not security-sensitive, but the current head includes unrelated dependency graph and workflow changes that need removal or explicit owner/security approval.

Review findings

  • [P1] Drop the unrelated repo-wide churn — .github/workflows/windows-testbox-probe.yml:40
  • [P1] Remove the unrelated dependency graph change — extensions/tokenjuice/package.json:11
Review details

Best possible solution:

Scrub or rebuild the branch so one canonical PR lands only the port-preflight fix and focused tests, with explicit maintainer acceptance of the SDK-visible helper shape or a Browser-private alternative.

Do we have a high-confidence way to reproduce the issue?

Yes. Current main and v2026.6.8 still use a hostless port probe before managed Chrome launch, and the PR body plus maintainer comment provide terminal proof for the IPv4-loopback occupant path.

Is this the best way to solve the issue?

No as currently submitted. The focused port fix is a maintainable direction, but the branch must drop unrelated dependency/workflow/repo-wide churn and get an explicit SDK API-shape decision before it is the best merge path.

Full review comments:

  • [P1] Drop the unrelated repo-wide churn — .github/workflows/windows-testbox-probe.yml:40
    The current head changes 255 files across workflows, docs, Codex, channels, plugins, agents, UI, scripts, and tests under a port-preflight fix title. Please rebuild or scrub the branch so this PR contains only the focused port helper, Browser caller, and regression tests.
    Confidence: 0.94
  • [P1] Remove the unrelated dependency graph change — extensions/tokenjuice/package.json:11
    This PR changes tokenjuice from 0.8.0 to 0.8.1 and also carries lock/shrinkwrap changes, but the stated fix is local port probing. The dependency graph guard blocks these external-PR dependency changes unless security/admin explicitly approves them, so restore the package and lockfile changes from main.
    Confidence: 0.96

Overall correctness: patch is incorrect
Overall confidence: 0.91

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 712e45daf137.

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body and maintainer comment include after-fix terminal/live-output proof for the IPv4-only loopback collision; that proof does not make the unrelated dependency and workflow changes merge-ready.

Label justifications:

  • P2: The underlying issue is a bounded Browser startup diagnostic bug with a clear workaround and limited blast radius.
  • merge-risk: 🚨 compatibility: The PR changes an SDK-exported helper signature and dependency/package surfaces that can affect plugin or upgrade behavior.
  • merge-risk: 🚨 automation: The PR changes a GitHub Actions workflow and Windows CI execution path unrelated to the stated port fix.
  • merge-risk: 🚨 other: The PR carries supply-chain dependency graph changes that are outside the stated fix and blocked by the dependency graph guard.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🦞 diamond lobster and patch quality is 🧂 unranked krab.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (terminal): The PR body and maintainer comment include after-fix terminal/live-output proof for the IPv4-only loopback collision; that proof does not make the unrelated dependency and workflow changes merge-ready.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body and maintainer comment include after-fix terminal/live-output proof for the IPv4-only loopback collision; that proof does not make the unrelated dependency and workflow changes merge-ready.
Evidence reviewed

Security concerns:

  • [medium] Unrelated dependency graph update — extensions/tokenjuice/package.json:11
    extensions/tokenjuice/package.json changes a runtime dependency and the PR also changes lock/shrinkwrap files, matching the dependency graph guard's blocked supply-chain surface for an external PR.
    Confidence: 0.96
  • [low] Unrelated workflow behavior change — .github/workflows/windows-testbox-probe.yml:194
    The PR adds Windows CI setup/install/test behavior and Defender exclusions to a workflow under a Browser port-fix title, which needs automation owner review or removal before merge.
    Confidence: 0.9

What I checked:

Likely related people:

  • vincentkoc: Current-main blame for ensurePortAvailable, the Browser preflight caller, and the SDK export points to commit 8f48f5e, though the checkout history is grafted so provenance is medium-confidence. (role: introduced or carried current implementation; confidence: medium; commits: 8f48f5e5ba67; files: src/infra/ports.ts, extensions/browser/src/browser/chrome.ts, src/plugin-sdk/security-runtime.ts)
  • steipete: Authored the PR follow-up commits that added port regression proof, Browser host probing, configured CDP host probing, and the latest mock typing change, and posted land-ready verification for the focused path. (role: active branch follow-up owner; confidence: medium; commits: 779ce77356c6, d9b5fe4b342a, b200b86da3fe; files: src/infra/ports.test.ts, extensions/browser/src/browser/chrome.ts, extensions/browser/src/browser/chrome.internal.test.ts)
  • wangwllu: Opened the canonical bug report and authored the narrower multi-family sibling candidate for the same ensurePortAvailable address-family failure. (role: canonical reporter and sibling fix author; confidence: medium; commits: 07238df4bf83; files: src/infra/ports.ts, src/infra/ports.test.ts, src/infra/ports-inspect.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@steipete

steipete commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Land-ready verification and landing for 65bbefde8c:

  • Local: 14 port-helper tests, 52 Browser Chrome lifecycle tests, and the Browser extension test-config typecheck passed.
  • Azure Crabbox cbx_993e8b8b2ea2 / run_4c549f71d168: an isolated Gateway and real openclaw browser start rejected an actual IPv4-only listener with PortInUseError.
  • Exact-SHA GitHub release gate 27762256042: all 126 jobs passed; Workflow Sanity also passed.
  • Fresh Codex autoreview: no accepted/actionable findings.
  • Landed through fix(infra): probe 127.0.0.1 in ensurePortAvailable to detect IPv4-only occupants #94394 as 4ec9d4a2b511933f9afa720d4618c4589274311b.

No known proof gap for the changed Chrome CDP collision path.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 18, 2026
@steipete
steipete requested a review from a team as a code owner June 18, 2026 11:11
@github-actions github-actions Bot added the dependencies-changed PR changes dependency-related files label Jun 18, 2026
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation channel: discord Channel integration: discord labels Jun 18, 2026
@steipete
steipete force-pushed the fix/ensure-port-available-ipv4-94379 branch from 590ba12 to 65bbefd Compare June 18, 2026 13:17
@github-actions github-actions Bot removed the dependencies-changed PR changes dependency-related files label Jun 18, 2026
@steipete

Copy link
Copy Markdown
Contributor

Merged via squash.

Thanks @Pandah97!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 automation 🚨 May affect CI, automerge, proof capture, label sync, or maintainer automation. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: S status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: ensurePortAvailable() pre-flight misses IPv4-only loopback occupant → Chrome CDP bind fails with misleading "HTTP 401"

2 participants