Skip to content

fix(browse): clarify localhost bind failures in sandboxes#1664

Open
spacegeologist wants to merge 1 commit into
garrytan:mainfrom
spacegeologist:fix-browse-startup-diagnostics-code-only
Open

fix(browse): clarify localhost bind failures in sandboxes#1664
spacegeologist wants to merge 1 commit into
garrytan:mainfrom
spacegeologist:fix-browse-startup-diagnostics-code-only

Conversation

@spacegeologist
Copy link
Copy Markdown

Reviewer Guide

  • browse/src/server.ts preserves the actual localhost bind failure from net.createServer().listen() and separates real EADDRINUSE port occupancy from sandbox / OS bind-denial failures such as EPERM.
  • browse/test/findport.test.ts adds regression coverage for both explicit BROWSE_PORT and random-port diagnostics, while keeping the old “port is in use” meaning for true EADDRINUSE.

Why

I have been experimenting with running gstack inside Codex and noticed that
browse can report random port exhaustion when the underlying issue is actually
a sandbox-denied 127.0.0.1 listen() call.

browse startup currently collapses every failed localhost bind attempt into a port-availability message like “No available port after 5 attempts” or “Port ... is in use.” In a sandboxed agent environment, including Codex, listen() can fail with EPERM even when the sampled port is not occupied. That sends the user and reviewer toward the wrong diagnosis: looking for port exhaustion instead of realizing that localhost binding is blocked by sandbox / OS permissions.

This patch keeps the successful path unchanged, but carries the original bind error through the diagnostic path. If the failure is EADDRINUSE, browse still reports an occupied port. If the failure is something else, the error now says that localhost binding is likely blocked and suggests allowing localhost binding, setting BROWSE_PORT to an approved port, or running from an unrestricted terminal.

Evidence

I hit this while dogfooding browse from a sandboxed Codex session. The installed gstack binary failed with the old message:

[browse] No available port after 5 attempts in range 10000-60000

After the local build, the same default sandbox scenario reports the actual class of failure:

[browse] Cannot bind localhost ports after 5 attempts in range 10000-60000. Last error: <sampled-port> (EPERM: Failed to listen at 127.0.0.1). This usually means the current sandbox or OS permissions are blocking localhost port binding, not that every sampled port is occupied. Allow localhost binding, set BROWSE_PORT to an approved port, or run browse from an unrestricted terminal.

When localhost binding is approved in the same environment, browse status becomes healthy, which confirms this is a diagnostic clarity issue rather than every random port being occupied.

Risk / Scope

  • Low runtime risk: successful port selection and server lifecycle are unchanged.
  • True EADDRINUSE still reports the existing occupied-port message.
  • This does not attempt to bypass sandbox restrictions or change permission behavior.

Verification

  • bun test browse/test/findport.test.ts
  • bun test browse/test/server-factory.test.ts
  • bun run build
  • git diff --check
  • Manual dogfood: browse/dist/browse status under the default sandbox now reports the EPERM bind-denial diagnostic instead of the misleading port-exhaustion message.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant