Skip to content

fix: make missing daemon errors actionable - #2356

Merged
shrey150 merged 7 commits into
mainfrom
kylejeong/gro-1908-cli-reliability
Jul 31, 2026
Merged

shrey150 merged 7 commits into
mainfrom
kylejeong/gro-1908-cli-reliability

Conversation

@Kylejeong2

@Kylejeong2 Kylejeong2 commented Jul 13, 2026

Copy link
Copy Markdown
Member

Summary

  • translate daemon socket ECONNREFUSED and ENOENT failures into a human-readable error
  • print the exact browse open command that restarts the requested session
  • document that API keys are forwarded to an already-running daemon and that browse stop is idempotent
  • preserve regression coverage for late environment variables and exit-code-zero cleanup

Root cause

The daemon client passed raw Unix socket errors through to users when the daemon disappeared between the readiness check and the request. Agents received ECONNREFUSED without a recovery command.

Impact

Agents now get an actionable daemon_not_running failure with the exact command needed to restart the session. Recovery command arguments are shell-quoted, and a daemon disappearing between status and stop is treated as an already-stopped session. Cleanup synchronizes with daemon startup so it preserves a replacement daemon that starts during the stop race. The bundled SKILL.md also makes the already-fixed env timing and stop behavior explicit.

E2E Test Matrix

Command / flow Observed output Confidence / sufficiency
pnpm --filter browse build TypeScript compilation and oclif manifest generation completed successfully. Proves the exact local CLI code under review builds; does not exercise a live browser.
pnpm --filter browse test:cli 25 test files passed; 366/366 tests passed. This includes deterministic daemon disappearance/restart races, adversarial recovery-command shell quoting, malformed CDP log payloads, and the complete CLI contract suite. Proves the full CLI suite passes against the completed local build on macOS; GitHub CI provides the Ubuntu/Windows matrix.
BROWSE_DAEMON_DIR=<temp dir> node packages/cli/bin/run.js stop --session no-daemon-smoke Exited 0 and printed { "stopped": false, "session": "no-daemon-smoke" }. Exercises the built CLI's real absent-daemon stop path and confirms its documented successful no-op behavior.
pnpm --filter browse lint Full-package Prettier, ESLint, and TypeScript checks completed successfully. Reproduces the CI lint pipeline locally and verifies the daemon changes, log reducer, tests, and inherited CLI lint baseline.

Linear: GRO-1908


Summary by cubic

Replaces raw socket errors with a clear daemon_not_running message and prints the exact, shell-quoted browse open recovery command. browse stop now treats a missing daemon as already stopped, validates ownership before cleanup, and avoids tearing down a daemon that restarts mid-race. Addresses Linear: https://linear.app/browserbase/issue/GRO-1908/cli-namespace-2027-dev-suggested-docs-updates.

  • Bug Fixes
    • Map ECONNREFUSED/ENOENT to daemon_not_running and show the precise, session-aware recovery command.
    • Make browse stop idempotent and safe: if the daemon vanished (no --force), return { stopped: false }; acquire a lock and verify daemon ownership before removing pid/socket/lock; preserve a replacement daemon started during the stop race (handles PID reuse).
    • Harden CDP log reduction: stricter parsing, ignore malformed payloads, and require numeric response statuses.
    • Docs: clarify BROWSERBASE_API_KEY is forwarded on every command and browse stop is idempotent; add troubleshooting for the new error.
    • Tests: cover the error message and shell-quoted recovery command (round-tripped through /bin/sh), stop race cleanup and restart preservation, PID reuse, and reduce-logs edge cases.

Written for commit 030c02a. Summary will update on new commits.

Review in cubic

@changeset-bot

changeset-bot Bot commented Jul 13, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 030c02a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@Kylejeong2
Kylejeong2 marked this pull request as ready for review July 15, 2026 18:57

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 4 files

Architecture diagram
sequenceDiagram
    participant Client as CLI / Test
    participant DaemonClient as sendDriverRequest()
    participant Socket as Unix Socket

    Client->>DaemonClient: openViaDaemon(session, url)
    DaemonClient->>DaemonClient: create socket connection
    DaemonClient->>Socket: connect(socketPath)
    Note over Socket: Daemon process not running
    Socket-->>DaemonClient: 'error' event

    alt Error code is ECONNREFUSED or ENOENT
        DaemonClient->>DaemonClient: isDaemonUnavailableError(error) → true
        DaemonClient->>DaemonClient: daemonNotRunningError(session, request)
        Note over DaemonClient: Builds CommandFailure with:<br/>message includes "browse open …"<br/>resultCode = "daemon_not_running"
        DaemonClient-->>Client: CommandFailure (actionable)
    else Other socket error (e.g., ECONNRESET)
        DaemonClient->>DaemonClient: failRequest(original error)
        DaemonClient-->>Client: raw error (unchanged)
    end
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/cli/src/lib/driver/daemon/client.ts
Comment thread packages/cli/src/lib/driver/daemon/client.ts Outdated
@shrey150 shrey150 closed this Jul 23, 2026
@shrey150 shrey150 reopened this Jul 23, 2026
@shrey150
shrey150 force-pushed the kylejeong/gro-1908-cli-reliability branch from b1d217f to 1cc01b4 Compare July 23, 2026 08:05
@shrey150
shrey150 changed the base branch from main to codex/pr2356-refresh-base July 23, 2026 08:07
@shrey150
shrey150 changed the base branch from codex/pr2356-refresh-base to main July 23, 2026 08:07

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 3 files (changes from recent commits).

Confidence score: 5/5

  • In packages/cli/src/lib/cloud/reduce-logs.ts, reduceLogs lacks focused unit tests around the newly guarded CDP payload branches, so malformed or partial records (including accepted error records) could slip through and cause silent parsing/filtering regressions in log reduction output—add targeted tests for console, log-entry, response-status, and related malformed-path cases.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/cli/src/lib/cloud/reduce-logs.ts">

<violation number="1" location="packages/cli/src/lib/cloud/reduce-logs.ts:57">
P3: `reduceLogs` has no focused unit coverage for the newly guarded CDP payload paths, so malformed/partial log records and accepted error records can regress unnoticed. Add tests for console, log-entry, response-status, and invalid payload cases.

(Based on your team's feedback about unit tests for new behavior.) [FEEDBACK_USED]</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/cli/src/lib/driver/daemon/client.ts Outdated
}

export function reduceLogs(raw: RawLog[], opts: ReduceLogsOptions = {}): unknown[] {
export function reduceLogs(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: reduceLogs has no focused unit coverage for the newly guarded CDP payload paths, so malformed/partial log records and accepted error records can regress unnoticed. Add tests for console, log-entry, response-status, and invalid payload cases.

(Based on your team's feedback about unit tests for new behavior.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/lib/cloud/reduce-logs.ts, line 57:

<comment>`reduceLogs` has no focused unit coverage for the newly guarded CDP payload paths, so malformed/partial log records and accepted error records can regress unnoticed. Add tests for console, log-entry, response-status, and invalid payload cases.

(Based on your team's feedback about unit tests for new behavior.) </comment>

<file context>
@@ -25,13 +40,24 @@ function paramsOf(e: RawLog): Record<string, any> {
 }
 
-export function reduceLogs(raw: RawLog[], opts: ReduceLogsOptions = {}): unknown[] {
+export function reduceLogs(
+  raw: RawLog[],
+  opts: ReduceLogsOptions = {},
</file context>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 7312a6f31 -- add focused reducer coverage for console, log-entry, response-status, exception, loading-failure, and malformed payload paths, plus runtime guards for malformed console argument containers and entries.

@shrey150
shrey150 changed the base branch from main to codex/pr2356-refresh-base July 23, 2026 08:38
@shrey150
shrey150 changed the base branch from codex/pr2356-refresh-base to main July 23, 2026 08:39
@shrey150 shrey150 added the bug Something isn't working label Jul 23, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 4 files (changes from recent commits).

Confidence score: 3/5

  • In packages/cli/src/lib/driver/daemon/client.ts, the stop-race path can treat a reused PID as the same daemon, leaving stale socket/PID files behind; this can block later starts with daemon_unresponsive and force manual recovery (--force/cleanup) — verify daemon identity before cleanup decisions (not PID liveness alone) and ensure stale artifacts are removed on mismatch.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/cli/src/lib/driver/daemon/client.ts">

<violation number="1" location="packages/cli/src/lib/driver/daemon/client.ts:128">
P2: A reused PID can leave the dead daemon's socket/PID files behind after this stop race, because liveness does not establish that the PID is this daemon. Later starts then report `daemon_unresponsive` and require `--force`; persist and validate a daemon-specific process identity (such as creation time) before retaining these files.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/cli/src/lib/driver/daemon/client.ts
@shrey150 shrey150 changed the title [GRO-1908] Make missing daemon errors actionable fix: make missing daemon errors actionable Jul 31, 2026
@shrey150
shrey150 merged commit 04c8ee4 into main Jul 31, 2026
38 checks passed
felipeofdev-ai pushed a commit to felipeofdev-ai/stagehand that referenced this pull request Aug 4, 2026
## Summary

- translate daemon socket `ECONNREFUSED` and `ENOENT` failures into a
human-readable error
- print the exact `browse open` command that restarts the requested
session
- document that API keys are forwarded to an already-running daemon and
that `browse stop` is idempotent
- preserve regression coverage for late environment variables and
exit-code-zero cleanup

## Root cause

The daemon client passed raw Unix socket errors through to users when
the daemon disappeared between the readiness check and the request.
Agents received `ECONNREFUSED` without a recovery command.

## Impact

Agents now get an actionable `daemon_not_running` failure with the exact
command needed to restart the session. Recovery command arguments are
shell-quoted, and a daemon disappearing between status and stop is
treated as an already-stopped session. Cleanup synchronizes with daemon
startup so it preserves a replacement daemon that starts during the stop
race. The bundled SKILL.md also makes the already-fixed env timing and
stop behavior explicit.

## E2E Test Matrix

| Command / flow | Observed output | Confidence / sufficiency |
| --- | --- | --- |
| `pnpm --filter browse build` | TypeScript compilation and oclif
manifest generation completed successfully. | Proves the exact local CLI
code under review builds; does not exercise a live browser. |
| `pnpm --filter browse test:cli` | 25 test files passed; 366/366 tests
passed. This includes deterministic daemon disappearance/restart races,
adversarial recovery-command shell quoting, malformed CDP log payloads,
and the complete CLI contract suite. | Proves the full CLI suite passes
against the completed local build on macOS; GitHub CI provides the
Ubuntu/Windows matrix. |
| `BROWSE_DAEMON_DIR=<temp dir> node packages/cli/bin/run.js stop
--session no-daemon-smoke` | Exited `0` and printed `{ "stopped": false,
"session": "no-daemon-smoke" }`. | Exercises the built CLI's real
absent-daemon stop path and confirms its documented successful no-op
behavior. |
| `pnpm --filter browse lint` | Full-package Prettier, ESLint, and
TypeScript checks completed successfully. | Reproduces the CI lint
pipeline locally and verifies the daemon changes, log reducer, tests,
and inherited CLI lint baseline. |

Linear:
[GRO-1908](https://linear.app/browserbase/issue/GRO-1908/cli-namespace-2027-dev-suggested-docs-updates)

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Replaces raw socket errors with a clear `daemon_not_running` message and
prints the exact, shell-quoted `browse open` recovery command. `browse
stop` now treats a missing daemon as already stopped, validates
ownership before cleanup, and avoids tearing down a daemon that restarts
mid-race. Addresses Linear:
https://linear.app/browserbase/issue/GRO-1908/cli-namespace-2027-dev-suggested-docs-updates.

- **Bug Fixes**
- Map `ECONNREFUSED`/`ENOENT` to `daemon_not_running` and show the
precise, session-aware recovery command.
- Make `browse stop` idempotent and safe: if the daemon vanished (no
`--force`), return `{ stopped: false }`; acquire a lock and verify
daemon ownership before removing pid/socket/lock; preserve a replacement
daemon started during the stop race (handles PID reuse).
- Harden CDP log reduction: stricter parsing, ignore malformed payloads,
and require numeric response statuses.
- Docs: clarify `BROWSERBASE_API_KEY` is forwarded on every command and
`browse stop` is idempotent; add troubleshooting for the new error.
- Tests: cover the error message and shell-quoted recovery command
(round-tripped through `/bin/sh`), stop race cleanup and restart
preservation, PID reuse, and reduce-logs edge cases.

<sup>Written for commit 030c02a.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/2356?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants