Skip to content

scan/get --json drop the agent-mode apply failure: exit 1 with failed: 0, the patch shown as "added", and no error anywhere (e.g. a read-only global ~/.m2) #424

Description

[agent] Found by the scheduled Maven bug-hunt routine (ledger #318).

Summary

When scan --mode agent / get download a patch and the nested apply step then fails, the --json envelope reports "status": "partial_failure" and exits 1. But it says "failed": 0, "applied": 0, lists the patch as "action": "added", and has no error code or message, on stdout or stderr. The human-mode run of the same command prints Error: Failed to patch pkg:maven/…: Permission denied (os error 13), so the cause is known; it just doesn't reach the JSON.

I found it with the global-mode (-g) checklist item "a global directory you can't write to must fail loudly with a clear error". The code path is not Maven-specific: get.rs keeps only a bool from the nested apply. I reproduced it with Maven only.

Impact

The exit code is right, but a CI job or automation that reads --json (the documented machine interface) can't tell what failed or why. The only per-patch record says added, and the counters show nothing failed. A consumer that keys on failed/patches[].action rather than the exit code reads this as "recorded, nothing failed".

Repro (Linux, Maven 3.9.11 local repository, run as a non-root user)

You need the agent-mode patch stub for pkg:maven/org.apache.commons/commons-text@1.10.0 (the shapes from tests/docker_e2e_maven.rs).

H=$(mktemp -d); REL=org/apache/commons/commons-text/1.10.0/commons-text-1.10.0.pom
mkdir -p $H/.m2/repository/$(dirname $REL); cp commons-text-1.10.0.pom $H/.m2/repository/$REL
chmod -R a+rX,go-w $H/.m2                      # root-owned, read-only for the user
W=$(mktemp -d); chmod 777 $W; cd $W
A="--api-url http://127.0.0.1:18997 --api-token fake --org org --ecosystems maven"
setpriv --reuid=65534 --regid=65534 --clear-groups env HOME=$H socket-patch scan -g --mode agent --yes --json $A
#   rc=1  {"status":"partial_failure", "apply":{"found":1,"downloaded":1,"failed":0,"applied":0,
#          "patches":[{"purl":"pkg:maven/...commons-text@1.10.0","action":"added",...}]}}   <- no error text
setpriv ... socket-patch get pkg:maven/org.apache.commons/commons-text@1.10.0 -g --yes --json $A
#   rc=1  same: failed 0, applied 0, action "added", no error
setpriv ... socket-patch scan -g --mode agent --yes $A           # human mode
#   Error: Failed to patch pkg:maven/org.apache.commons/commons-text@1.10.0: Permission denied (os error 13)
#   Summary: 0 of 1 targeted patch applied, 0 already patched, 1 failed, 0 not found on disk
setpriv ... socket-patch apply -g --json --offline --ecosystems maven
#   standalone apply is fine: events[0] = {"action":"failed","errorCode":"apply_failed","error":"Permission denied (os error 13)"}

Each command was run twice, in fresh workdirs, with the same result. No permission text appears in the JSON or on stderr in either JSON run.

Expected vs actual

  • Expected: the JSON carries the per-patch apply outcome, the same {action:"failed", errorCode:"apply_failed", error} the standalone apply --json emits. The counters agree with the status (failed ≥ 1, or an apply failure count). CLI_CONTRACT.md's patches[] entry shape for get and scan --apply says records "carry the same metadata regardless of which command" produced them, and the human path for this same run reports 1 failed.
  • Actual: failed: 0, action: "added", no error. Only the exit code and status show the failure.

Matrix

OS Maven local repository scan -g --mode agent --json get -g --json human mode apply -g --json
Linux 3.9.11 layout, read-only fail (no error, failed 0) fail (no error, failed 0) pass (error printed) pass (apply_failed event)

macOS and Windows are untested. The failure is in the JSON assembly, which doesn't depend on the OS. Other ecosystems are probably affected too (same code), but I only checked Maven.

Tested on: main 2463257 (v5 consolidation, #277). Not bisected.

Suspect code

  • crates/socket-patch-cli/src/commands/get.rs:2469: run_nested_apply(...) returns only a bool. The nested apply's events (with errorCode/error) are dropped, and the envelope at get.rs:2487-2495 fills failed from batch.failed (download failures only) and applied from downloaded or 0.
  • get.rs:3453 (the second apply_failed site) has the same shape.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions