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 28, 2026, 5:08 PM ET / 21:08 UTC.

ClawSweeper review

What this changes

The branch adds an ENOENT-specific spawn-error detail code and actionable remediation text for raw ACP agent launches, with CLI and error-normalization regression coverage.

Merge readiness

⚠️ Ready for maintainer review - 4 items remain

Keep open: current main still emits only the generic spawn failure, and this is a coherent, narrowly scoped candidate fix. The branch needs a rebase to resolve its changelog conflict and maintainer approval for the new permanent machine-readable error convention.

Priority: P2
Reviewed head: 0930ad093c58d98c653ed6e61c2e7c69950bc3a5
Owner decision: Required. See Decision needed.

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) A narrow, well-covered implementation with credible real CLI proof; rebasing and approving the new public detail-code convention remain before merge.
Proof confidence 🦞 diamond lobster (5/6) Sufficient (terminal): The changed production owner is AgentSpawnError, which receives the real child-process error from AcpClient’s spawn-event wait; the supplied body records an after-fix built-CLI run in a clean temporary HOME for absent-command and missing-working-directory ENOENT cases, with RUNTIME plus AGENT_SPAWN_ENOENT observed and a non-ENOENT generic control.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Verified Sufficient (terminal): The changed production owner is AgentSpawnError, which receives the real child-process error from AcpClient’s spawn-event wait; the supplied body records an after-fix built-CLI run in a clean temporary HOME for absent-command and missing-working-directory ENOENT cases, with RUNTIME plus AGENT_SPAWN_ENOENT observed and a non-ENOENT generic control.
Evidence reviewed 8 items Introduced production classification: The changed constructor recognizes an ENOENT cause, preserves the broad runtime classification, and adds the new detail code; the pinned introduction diff attributes this hunk to the PR.
Actual spawn-error boundary: The ACP client awaits the child-process spawn event and wraps its error in AgentSpawnError, so the changed constructor receives the real launch ENOENT rather than an ACP protocol error.
Current main still lacks the behavior: Current main retains the generic AgentSpawnError message with no ENOENT-specific detailCode, so the central PR behavior is neither implemented nor obsolete.
Findings None None.
Security None None.

How this fits together

acpx resolves an agent command and starts its process before ACP session initialization. Process-launch failures are wrapped and normalized into text and JSON CLI errors for people and embedding automation.

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

Decision needed

Question Recommendation
Should AGENT_SPAWN_ENOENT become an intentional permanent detailCode in acpx’s public machine-error contract? Approve the additive contract after rebase: Resolve the current changelog conflict and accept the documented ENOENT detail code while retaining RUNTIME and the generic path for all other spawn failures.

Why: VISION.md and AGENTS.md treat output shapes and naming conventions as long-term API surface; source review can validate the implementation but cannot choose the permanent convention.

Before merge

  • Resolve merge risk (P1) - AGENT_SPAWN_ENOENT would become a permanent machine-output convention, so maintainers need to intentionally accept that public contract.
  • Resolve merge risk (P1) - The PR currently conflicts with main in CHANGELOG and needs a rebase before its final merge result can be reviewed.
  • Complete next step (P2) - This needs a routine rebase plus maintainer approval of a new permanent public output convention; there is no mechanical defect to dispatch.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Production versus test delta production +11/-1, tests +78, docs/changelog +9 The small production change has direct CLI and normalization coverage for both classified and generic spawn-failure paths.

Root-cause cluster

Relationship: fixed_by_candidate
Canonical: #510
Summary: This PR explicitly targets the same raw-agent spawn ENOENT diagnostic gap tracked by the open issue and supplies its proposed implementation.

Members:

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

Merge-risk options

Maintainer options:

  1. Decide the mitigation before merge
    Rebase onto current main, then retain the narrow ENOENT classification only if maintainers approve AGENT_SPAWN_ENOENT as a stable additive output contract while leaving RUNTIME and generic non-ENOENT behavior unchanged.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Technical review

Best possible solution:

Rebase onto current main, then retain the narrow ENOENT classification only if maintainers approve AGENT_SPAWN_ENOENT as a stable additive output contract while leaving RUNTIME and generic non-ENOENT behavior unchanged.

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

Yes, with high source confidence: current main still wraps the child-process error as AgentSpawnError without preserving ENOENT, and the supplied clean-release command exercises that raw-command path. This review did not execute target code in the read-only checkout.

Is this the best way to solve the issue?

Unclear pending product direction: classifying the actual spawn boundary is the narrow implementation, but a new stable detailCode requires explicit approval as public output API.

AGENTS.md: found and applied where relevant.

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

Labels

Label justifications:

  • P2: This is a bounded diagnostic and machine-output improvement for raw custom-agent launches, without evidence of a broader outage.
  • 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 (terminal): The changed production owner is AgentSpawnError, which receives the real child-process error from AcpClient’s spawn-event wait; the supplied body records an after-fix built-CLI run in a clean temporary HOME for absent-command and missing-working-directory ENOENT cases, with RUNTIME plus AGENT_SPAWN_ENOENT observed and a non-ENOENT generic control.
  • proof: sufficient: Contributor real behavior proof is sufficient. The changed production owner is AgentSpawnError, which receives the real child-process error from AcpClient’s spawn-event wait; the supplied body records an after-fix built-CLI run in a clean temporary HOME for absent-command and missing-working-directory ENOENT cases, with RUNTIME plus AGENT_SPAWN_ENOENT observed and a non-ENOENT generic control.

Evidence

What I checked:

  • Introduced production classification: The changed constructor recognizes an ENOENT cause, preserves the broad runtime classification, and adds the new detail code; the pinned introduction diff attributes this hunk to the PR. (src/errors.ts:47, 0930ad093c58)
  • Actual spawn-error boundary: The ACP client awaits the child-process spawn event and wraps its error in AgentSpawnError, so the changed constructor receives the real launch ENOENT rather than an ACP protocol error. (src/acp/client.ts:927, 0930ad093c58)
  • Current main still lacks the behavior: Current main retains the generic AgentSpawnError message with no ENOENT-specific detailCode, so the central PR behavior is neither implemented nor obsolete. (src/errors.ts:46, ef6b81e71756)
  • Focused regression coverage: The branch covers raw-command and missing-working-directory ENOENT cases, preserves RUNTIME, and verifies non-ENOENT failures remain generic. (test/cli.test.ts:348, 0930ad093c58)
  • Provided real-run proof: The complete supplied PR body records a clean temporary-home built-CLI run, failed-first focused tests, after-fix text/JSON output, and a non-ENOENT control. (0930ad093c58)
  • Rebase is required: Current main added the v0.13.2 release section while the branch replaces that location with its Unreleased entry; GitHub reports the PR as dirty and no pinned test merge is available. (CHANGELOG.md:12, ef6b81e71756)

Likely related people:

  • Alex Knight: The available pre-PR path history identifies this contributor as the latest touch on the shared errors module. (role: recent error-path contributor; confidence: medium; commits: eb132177bd90; files: src/errors.ts)
  • Peter Steinberger: The latest available pre-PR history for the client that wraps spawn failures points to this contributor. (role: recent ACP-client contributor; confidence: medium; commits: 1ee1e82c2357; files: src/acp/client.ts)
  • Sebastien Tardif: Recent available history on the process-helper module containing the spawn-event waiter points to this contributor. (role: recent process-helper contributor; confidence: medium; commits: 4d9ea54f1f89; files: src/acp/client-process.ts)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Rebase onto current main and resolve the CHANGELOG conflict while preserving the Unreleased entry.
  • Obtain maintainer approval for AGENT_SPAWN_ENOENT as a stable public detailCode.

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.

History

Review history (1 earlier review cycle)
  • reviewed 2026-08-21T05:04:25.412Z sha 0930ad0 :: needs maintainer review before merge. :: none

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