Skip to content

fix: explain raw agent spawn ENOENT failures - #511

Open
anyech wants to merge 1 commit into
openclaw:mainfrom
anyech:fix/agent-spawn-enoent-diagnostic
Open

fix: explain raw agent spawn ENOENT failures#511
anyech wants to merge 1 commit into
openclaw:mainfrom
anyech:fix/agent-spawn-enoent-diagnostic

Conversation

@anyech

@anyech anyech commented Aug 21, 2026

Copy link
Copy Markdown

Closes #510

What Problem This Solves

Fixes an issue where users launching a raw custom ACP agent would receive only Failed to spawn agent command: <name> when process creation failed with ENOENT. The error discarded the launch classification, so operators and embedding runtimes could not distinguish this missing-path condition from other startup failures or select a useful next step.

Why This Change Was Made

AgentSpawnError now preserves the existing broad RUNTIME code while adding detailCode=AGENT_SPAWN_ENOENT only when the actual child-process cause has code=ENOENT. Its message gives qualified remediation covering the executable, interpreter, effective PATH, working directory, and configured argv without assuming the command binary is always the missing path.

Unknown positional agents remain valid raw commands. Non-ENOENT spawn failures keep the prior generic message and metadata. The existing machine-error strategy and changelog document the additive contract.

User Impact

Operators get a useful explanation at the failure boundary instead of debugging unrelated ACP session, provider, or protocol paths. Embedding runtimes can branch on a stable detail code without breaking consumers that already rely on acpxCode=RUNTIME.

Evidence

Behavior addressed

Raw custom-agent process creation with an underlying ENOENT lost the cause and remediation in both text and JSON output.

Real setup tested

A clean disposable source checkout and a dedicated credential-free temporary HOME were used. The final CLI processes ran under env -i; no Gateway, production state, provider credentials, or external ACP agent was involved.

Exact steps or command run after this patch

stage_home="$(mktemp -d)"
env -i HOME="$stage_home" PATH=/usr/bin:/bin COREPACK_HOME="$stage_home/corepack" \
  corepack enable --install-directory "$stage_home/bin" pnpm

env -i HOME="$stage_home" PATH="$stage_home/bin:/usr/bin:/bin" \
  COREPACK_HOME="$stage_home/corepack" CI=1 pnpm install --frozen-lockfile
env -i HOME="$stage_home" PATH="$stage_home/bin:/usr/bin:/bin" \
  COREPACK_HOME="$stage_home/corepack" CI=1 pnpm run build:test
env -i HOME="$stage_home" PATH=/usr/bin:/bin \
  node --test --test-name-pattern 'spawn ENOENT|non-ENOENT spawn|actionable text and JSON detail' \
  dist-test/test/error-normalization.test.js dist-test/test/cli.test.js
env -i HOME="$stage_home" PATH="$stage_home/bin:/usr/bin:/bin" \
  COREPACK_HOME="$stage_home/corepack" CI=1 pnpm run check
env -i HOME="$stage_home" PATH="$stage_home/bin:/usr/bin:/bin" \
  COREPACK_HOME="$stage_home/corepack" CI=1 pnpm run check:docs

env -i HOME="$stage_home" PATH=/usr/bin:/bin \
  node dist/cli.js oc-test-missing-acp-agent exec ping
env -i HOME="$stage_home" PATH=/usr/bin:/bin \
  node dist/cli.js --format json oc-test-missing-acp-agent exec ping

Evidence after fix

Failed-first focused tests produced two expected failures before the production edit: the CLI still emitted only the generic message, and normalized JSON had no detail code. After the fix, the same three-test slice passed:

CLI reports actionable text and JSON detail for a missing raw agent command: PASS
normalizeOutputError preserves spawn ENOENT as an additive detail: PASS
normalizeOutputError keeps non-ENOENT spawn failures generic: PASS

The built JSON output now preserves the broad code and adds narrow detail:

{
  "error": {
    "data": {
      "acpxCode": "RUNTIME",
      "detailCode": "AGENT_SPAWN_ENOENT",
      "origin": "cli"
    }
  }
}

pnpm run check passed with 938 tests and the configured coverage gates. pnpm run check:docs also passed. The automated CLI test now covers both an absent raw-agent path and an invalid working directory. A separate manual built-CLI EACCES control used a present non-executable file and retained the old generic result with no new detail.

Observed result after fix

Text output identifies a missing executable, interpreter, working directory, or other required launch path and suggests checking the command, effective PATH, working directory, or configured argv. JSON consumers receive additive AGENT_SPAWN_ENOENT detail while the top-level runtime classification remains unchanged.

What was not tested

  • A live external ACP adapter or provider request, because process creation fails before ACP initialization.
  • Production Gateway/config/state; testing intentionally remained isolated.
  • Windows raw command strings, which already use the repository's structured-argv policy and have separate platform-specific issue history.

AI assistance

AI-assisted implementation and review. I inspected the owner path, reproduced the failure on the current release, and verified the final source and tests directly.

@anyech
anyech requested a review from a team as a code owner August 21, 2026 05:02
@clawsweeper

clawsweeper Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

@clawsweeper clawsweeper Bot added P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. 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 Aug 21, 2026
@clawsweeper

clawsweeper Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed August 21, 2026, 1:04 AM ET / 05:04 UTC.

ClawSweeper review

What this changes

This PR classifies raw custom-agent process-spawn ENOENT failures with an additive machine detail code and actionable text, while retaining the existing broad runtime code for all consumers.

Merge readiness

Ready for maintainer review

Keep open: this is a focused, source-backed fix for the linked current bug, and current main/release v0.13.1 still emits only the generic spawn failure.

Priority: P2
Reviewed head: 0930ad093c58d98c653ed6e61c2e7c69950bc3a5

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) The patch is focused, preserves the established broad error contract, and includes credible real CLI proof plus regression coverage.
Proof confidence 🦞 diamond lobster (5/6) Sufficient (live_output): The PR body supplies clean-environment after-fix terminal commands and observed text/JSON output for the real CLI spawn boundary.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Verified Sufficient (live_output): The PR body supplies clean-environment after-fix terminal commands and observed text/JSON output for the real CLI spawn boundary.
Evidence reviewed 6 items Current release still has the reported behavior: Current main's AgentSpawnError preserves only the generic message and cause, with no ENOENT-specific detail code; current main is also v0.13.1.
The affected custom-agent path is supported: Repository documentation says unknown positional agent names become raw commands, and the client wraps the actual child-process spawn error in AgentSpawnError.
Patch preserves compatibility while adding the narrow classification: The branch checks the real spawn error's code, adds AGENT_SPAWN_ENOENT only for ENOENT, and otherwise retains the existing generic message and runtime normalization path.
Findings None None.
Security None None.

Live Verification

Command: pnpm run dev -- --format json /definitely/missing-acp-agent exec ping

Result: PASS (completed)

pnpm run dev -- --format json /definitely/missing-acp-agent exec ping
runner@runnervm76f27:/tmp/clawsweeper-live-proof-511-UYY9r1/target$ pnpm run dev -- --format json /definitely/missing-acp-agent exec ping

› acpx@0.13.1 dev /tmp/clawsweeper-live-proof-511-UYY9r1/target
› tsx src/cli.ts -- --format json /definitely/missing-acp-agent exec ping

{"jsonrpc":"2.0","id":null,"error":{"code":-32603,"message":"Failed to spawn agent command: /definitely/missing-acp-agent. The agent process could not start bec
ause a required executable, interpreter, working directory, or other launch path was not found. Check the command, effective PATH, and working directory, or ver
ify the custom agent's configured argv.","data":{"acpxCode":"RUNTIME","detailCode":"AGENT_SPAWN_ENOENT","origin":"cli","sessionId":"unknown"}}}
pnpm run dev -- --format json /definitely/missing-acp-agent exec ping
 ELIFECYCLE  Command failed with exit code 1.
runner@runnervm76f27:/tmp/clawsweeper-live-proof-511-UYY9r1/target$ pnpm run dev -- --format json /definitely/missing-acp-agent exec ping

› acpx@0.13.1 dev /tmp/clawsweeper-live-proof-511-UYY9r1/target
› tsx src/cli.ts -- --format json /definitely/missing-acp-agent exec ping

{"jsonrpc":"2.0","id":null,"error":{"code":-32603,"message":"Failed to spawn agent command: /definitely/missing-acp-agent. The agent process could not start bec
ause a required executable, interpreter, working directory, or other launch path was not found. Check the command, effective PATH, and working directory, or ver
ify the custom agent's configured argv.","data":{"acpxCode":"RUNTIME","detailCode":"AGENT_SPAWN_ENOENT","origin":"cli","sessionId":"unknown"}}}
 ELIFECYCLE  Command failed with exit code 1.
runner@runnervm76f27:/tmp/clawsweeper-live-proof-511-UYY9r1/target$






























Assertions:

  • PASS expect_output: AGENT_SPAWN_ENOENT

How this fits together

The CLI resolves a built-in or custom ACP agent command, starts its child process, and normalizes launch failures for terminal and JSON consumers. This change improves the diagnostic produced at the process-spawn boundary before ACP session initialization begins.

flowchart LR
  A[CLI custom agent input] --> B[Command resolution]
  B --> C[Agent process spawn]
  C --> D{Spawn result}
  D -->|ENOENT| E[Actionable runtime error]
  D -->|Other failure| F[Generic runtime error]
  E --> G[Terminal and JSON output]
  F --> G
Loading

Before merge

None.

Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Focused change surface production +10 net lines; tests +78; docs/changelog +9 across 5 files The implementation is small and the added regression coverage is substantially larger than the runtime change.

Technical review

Best possible solution:

Land the narrow diagnostic improvement after ordinary PR checks, keeping the broad RUNTIME classification and generic handling for non-ENOENT failures unchanged.

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

Yes. The supported raw-command path, spawn-error wrapper, and current generic output are directly traceable in source, and the PR supplies a focused current-release CLI reproduction.

Is this the best way to solve the issue?

Yes. Classifying the actual child-process ENOENT at the existing spawn-error boundary is narrower and more reliable than preflighting command paths or changing raw-command resolution.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 2d735cf18220.

Labels

Label changes:

  • add P2: This repairs a deterministic diagnostic failure for custom-agent launches without affecting already-running ACP sessions.
  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body supplies clean-environment after-fix terminal commands and observed text/JSON output for the real CLI spawn boundary.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body supplies clean-environment after-fix terminal commands and observed text/JSON output for the real CLI spawn boundary.

Label justifications:

  • P2: This repairs a deterministic diagnostic failure for custom-agent launches without affecting already-running ACP sessions.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body supplies clean-environment after-fix terminal commands and observed text/JSON output for the real CLI spawn boundary.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body supplies clean-environment after-fix terminal commands and observed text/JSON output for the real CLI spawn boundary.

Evidence

What I checked:

  • Current release still has the reported behavior: Current main's AgentSpawnError preserves only the generic message and cause, with no ENOENT-specific detail code; current main is also v0.13.1. (src/errors.ts:47, 2d735cf18220)
  • The affected custom-agent path is supported: Repository documentation says unknown positional agent names become raw commands, and the client wraps the actual child-process spawn error in AgentSpawnError. (src/acp/client.ts:934, 0930ad093c58)
  • Patch preserves compatibility while adding the narrow classification: The branch checks the real spawn error's code, adds AGENT_SPAWN_ENOENT only for ENOENT, and otherwise retains the existing generic message and runtime normalization path. (src/errors.ts:47, 0930ad093c58)
  • CLI coverage exercises both text and structured output: The new CLI test covers an absent raw command and an invalid working directory, asserting RUNTIME plus the additive detail code. (test/cli.test.ts:348, 0930ad093c58)
  • Current-main ownership provenance: Blame attributes the current main AgentSpawnError and spawn-wrapper lines to Peter Steinberger; the locally available history is shallow, so this establishes current-line ownership rather than original feature authorship. (src/errors.ts:43, 2d735cf18220)
  • Contributor after-fix proof: The PR body provides clean-environment built-CLI commands, after-fix text/JSON output, focused test results, and a non-ENOENT control; no dependency contract beyond Node child-process spawn semantics is claimed. (0930ad093c58)

Likely related people:

  • Peter Steinberger: Current-main blame covers both the existing AgentSpawnError implementation and its client spawn wrapper; available local history is shallow. (role: current-main area contributor; confidence: medium; commits: 2d735cf18220; files: src/errors.ts, src/acp/client.ts)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
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.

Workflow

  • 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.

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

Labels

P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. 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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[UX] Raw custom-agent spawn ENOENT loses its cause and remediation

1 participant