Skip to content

Clarify sandbox port-bind failures in browse startup#871

Open
tichenm wants to merge 3 commits intogarrytan:mainfrom
tichenm:fix/browse-sandbox-port-bind
Open

Clarify sandbox port-bind failures in browse startup#871
tichenm wants to merge 3 commits intogarrytan:mainfrom
tichenm:fix/browse-sandbox-port-bind

Conversation

@tichenm
Copy link
Copy Markdown

@tichenm tichenm commented Apr 7, 2026

Summary

  • distinguish permission-denied localhost bind failures from real port contention in browse startup
  • preserve explicit BROWSE_PORT handling and add targeted regression coverage
  • document the sandbox-specific failure mode in troubleshooting

Root cause

In sandboxed environments, binding 127.0.0.1:<port> can fail with EPERM or EACCES. Browse treated all bind failures as unavailable ports, retried 5 random ports, and then surfaced the misleading error No available port after 5 attempts.

What changed

  • extracted port probing into browse/src/port.ts
  • treat EADDRINUSE as real contention, but surface EPERM / EACCES as environment restrictions
  • route explicit BROWSE_PORT through the same classification logic
  • added regression tests for random-port and explicit-port permission failures
  • added troubleshooting notes for stale installs that still show the legacy message

Verification

  • bun test browse/test/findport.test.ts
  • bun test browse/test/
  • sandbox startup check now reports Local port bind was blocked by the environment (EPERM)
  • escalated startup check still reaches healthy status

tim added 3 commits April 6, 2026 23:08
Sandboxed localhost binds can fail with EPERM or EACCES, but browse treated every bind error as either port contention or generic exhaustion. This extracts port probing into a dedicated helper, preserves explicit BROWSE_PORT handling, and surfaces permission-denied failures with actionable guidance instead of retrying into a misleading exhaustion message.

Constraint: Some sandboxed environments reject 127.0.0.1 binds with EPERM/EACCES instead of EADDRINUSE
Rejected: Keep the generic retry loop | misreports permission failures as port exhaustion
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Treat EPERM/EACCES as environment restrictions, not port contention, unless startup semantics are redesigned end-to-end
Tested: bun test browse/test/findport.test.ts; bun test browse/test/; sandbox and escalated browse startup checks
Not-tested: Non-sandbox environments that deny binds for reasons other than EPERM/EACCES
Browse now reports permission-denied bind failures clearly, but users upgrading from older installs can still encounter the legacy "No available port" message and misdiagnose it as port exhaustion. Add a troubleshooting note that distinguishes sandbox restrictions from real port contention and points users at rebuild or upgrade as the fix.

Constraint: README troubleshooting needs to help both fresh installs and stale installs already in the field
Rejected: Leave the explanation only in runtime error text | stale installs still surface the old misleading message
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep troubleshooting aligned with actual browse startup errors when startup diagnostics change
Tested: README diff reviewed against current browse error strings
Not-tested: Generated skill docs or website copies of this troubleshooting text
The port classification fix covers server startup directly, but the user-facing failure path usually goes through the CLI auto-start flow. Add a lifecycle regression test that boots the CLI with an explicit BROWSE_PORT and verifies the spawned server keeps that requested port in its state file.

Constraint: The CLI startup path must stay testable without launching Chromium, so the regression uses BROWSE_HEADLESS_SKIP and a temporary state file
Rejected: String-match the source for BROWSE_PORT forwarding | would miss real wiring regressions in the subprocess startup path
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep this test focused on preserved port wiring, not incidental status output formatting
Tested: bun test browse/test/commands.test.ts -t "explicit BROWSE_PORT is preserved when CLI auto-starts the server"; bun test browse/test/findport.test.ts
Not-tested: Full browse/test/ suite after adding this extra CLI lifecycle coverage
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