Symptom
When the server rejects a request with 400 validation_failed, the CLI prints only the generic envelope sentence:
error: The request did not match what this endpoint expects (400 validation_failed)
The same under --json:
{ "error": "The request did not match what this endpoint expects (400 validation_failed)", "causes": [] }
The server's envelope carries a details map (path -> messages, @imogen/shared error.ts:12) naming the offending field and index. The CLI drops it, so a user cannot tell which argument was wrong without the server log.
Reproduction
imogen trash <a-string-that-is-not-a-uuid> (or any request the server's schema refuses).
- Read the error. It names no field, in prose or under
--json.
Expected
Prose: the envelope sentence, then one line per details entry, e.g.
error: The request did not match what this endpoint expects (400 validation_failed)
assetIds.3: Invalid UUID
--json: a details key carrying the map verbatim, so a script gets the API's own payload unrenamed (CLAUDE.md, Every CLI command answers twice).
Affected repos
Only this one. The SDK already exposes the map through Error::details() (imogen-sdk/rust/src/error.rs:74); nothing on the wire changes.
Suspected cause
report() in src/main.rs:58-70 formats the anyhow chain and nothing else. It never downcasts to imogen_sdk::Error and never reads details().
Bar
cargo test --locked && cargo fmt --check && cargo clippy --all-targets --locked -- -D warnings && cargo build --release --locked. A test that an Error::Api with a details map renders each entry, in prose and as a details key under --json, is the one that would have caught this.
Context
Split out of #15 during triage on 2026-09-08. That issue's multi-id 400 has not been reproduced on a pinned build, and this gap is exactly why: the details map would have named the field in ten seconds. Same shape as ergofobe/imogen-android#22, which was undiagnosable until the Android client started recording details.
Symptom
When the server rejects a request with
400 validation_failed, the CLI prints only the generic envelope sentence:The same under
--json:{ "error": "The request did not match what this endpoint expects (400 validation_failed)", "causes": [] }The server's envelope carries a
detailsmap (path -> messages,@imogen/sharederror.ts:12) naming the offending field and index. The CLI drops it, so a user cannot tell which argument was wrong without the server log.Reproduction
imogen trash <a-string-that-is-not-a-uuid>(or any request the server's schema refuses).--json.Expected
Prose: the envelope sentence, then one line per
detailsentry, e.g.--json: adetailskey carrying the map verbatim, so a script gets the API's own payload unrenamed (CLAUDE.md, Every CLI command answers twice).Affected repos
Only this one. The SDK already exposes the map through
Error::details()(imogen-sdk/rust/src/error.rs:74); nothing on the wire changes.Suspected cause
report()insrc/main.rs:58-70formats theanyhowchain and nothing else. It never downcasts toimogen_sdk::Errorand never readsdetails().Bar
cargo test --locked && cargo fmt --check && cargo clippy --all-targets --locked -- -D warnings && cargo build --release --locked. A test that anError::Apiwith adetailsmap renders each entry, in prose and as adetailskey under--json, is the one that would have caught this.Context
Split out of #15 during triage on 2026-09-08. That issue's multi-id 400 has not been reproduced on a pinned build, and this gap is exactly why: the
detailsmap would have named the field in ten seconds. Same shape as ergofobe/imogen-android#22, which was undiagnosable until the Android client started recordingdetails.