Repository navigation
An unparseable .socket/manifest.json is reported under five different --json error codes depending on the command #931
Description
[agent] Filed by the scheduled architecture audit routine (CLI and core). Register: register comment.
Kind: bug. Source: new finding, register row C52; child 1 of #930 (C13).
Problem
read_manifest reports malformed JSON or a schema violation as io::ErrorKind::InvalidData, and anything else as a plain I/O error. The contract's top-level code table names manifest_invalid for "exists but is unparseable" and manifest_unreadable for an I/O error. Only list and remove implement that split, and each has its own copy of it (list.rs, remove.rs). Every other command picks its own code for the same Err:
| Command | Code for an unparseable manifest | Site |
|---|---|---|
list, remove |
manifest_invalid |
above |
apply --check, vendor --check, vex |
manifest_unreadable |
apply.rs#L519-L527, vendor.rs#L996-L999, vex.rs#L1166 |
apply |
apply_failed (generic pipeline error) |
apply.rs#L1356 |
repair |
repair_failed (generic pipeline error) |
repair.rs#L224-L227 |
vendor |
invalid_manifest (undocumented) |
vendor.rs#L1712-L1713 |
rollback |
the bare parser message as error (no code; #704) |
rollback.rs#L1199-L1203 |
So apply and apply --check disagree with each other, and so do vendor and vendor --check. A CI wrapper that routes on error.code needs five spellings to recognize one corrupt file.
Proof by execution (debug build on 9c43dfc, run twice with identical results). In a project holding package.json and .socket/manifest.json = {"patches": {, each command ran with --json under env -i:
list exit=1 code=manifest_invalid
remove pkg:npm/x@1.0.0 exit=1 code=manifest_invalid
apply --check exit=1 code=manifest_unreadable
vendor --check exit=1 code=manifest_unreadable
vex --output o.json exit=2 code=manifest_unreadable
apply exit=1 code=apply_failed
repair --offline exit=1 code=repair_failed
vendor exit=1 code=invalid_manifest
rollback --offline exit=1 error="Failed to parse manifest JSON: EOF while parsing an object at line 2 column 0"
Symptoms
None filed. Impact: a machine-readable contract that differs by command for one condition, and one undocumented code. The change is small.
Proposed change
- Add one mapping next to
read_manifestin core (for examplemanifest_load_error_code(&io::Error) -> &'static str, which becomes anErrorCodeonce Tracking: emit every --json error code from one typed ErrorCode registry checked against the contract tables #930's child 2 lands) that returnsmanifest_invalidforInvalidDataandmanifest_unreadableotherwise. - Call it from
list,remove,apply(both paths),vendor(both paths) andrepair, so thatapplyandrepairstop wrapping the load error in their generic pipeline code. - Delete the two hand-written
InvalidDatasplits inlist.rsandremove.rs, and the undocumentedinvalid_manifestliteral. - Contract: add
apply,repairandvendorto the Subcommands column of the two rows.
Size and scope
About 6 CLI files and one core helper, roughly 60 changed production lines plus tests. Out of scope:
vex. The contract documents thatvexreports an unparseable manifest asmanifest_unreadablewith exit 2, so moving it tomanifest_invalidis a contract change. Either leave it alone, or change it with the contract row in the same PR if the maintainer agrees.rollback's bare-stringerror, which waits on Decide: one shape for the--jsontop-levelerror(scan and get emit both a string and a {code, message} object) #704 (Tracking: emit every --json error code from one typed ErrorCode registry checked against the contract tables #930 child 5).
Acceptance criteria
- With an unparseable manifest,
list,remove,apply,apply --check,repair,vendorandvendor --checkall reporterror.code == "manifest_invalid"under--json, and their exit codes are unchanged. - A manifest that can't be read (for example a directory at
.socket/manifest.json) reportsmanifest_unreadableon the same commands. - Add a regression test that runs that command matrix against one corrupt fixture.
-
invalid_manifestno longer appears in the source. - The existing
list/removemanifest_invalidtests stay green.
Dependencies
None; it can land before #930's child 2. It blocks nothing.
Activity
audit-core: C13 decomposed (#930, #931), C52 new finding
refactor: re-rank queue, add #931 (C52)
mikolalysenko commentedon Oct 6, 2026
[agent] Triaged as
priority:p3(general CLI / error contract). Not a duplicate, and no open PR covers it. It is child 1 of the #930 tracking issue. The code sites it names on9c43dfcmatch currentmain.Generated by Claude Code
mikolalysenko commentedon Oct 9, 2026
v5 triage: P3, not a release blocker. Keep invalid-manifest error-code uniformity as P3. It does not block a valid-lockfile first run; do not grow recovery/guard work for v5.
This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.
Lay the envelope foundation every --json command will share
Map manifest load failures to one error code on every envelope command (
Document the unified manifest-load codes and remove/repair event shapes