Report what serde objected to when a response will not parse - #82
Merged
Conversation
A response Graph considers successful but this crate cannot deserialize was reported as `Failed to parse API response: error decoding response body`, which names neither the offending value nor where it sat. `reqwest::Error` keeps serde's account of the mismatch one level down its source chain and `Display` never reaches it, so the only way to diagnose a schema drift was to capture the response by hand — which is how osodevops#69 came to need a live account to find a one-word type error. `describe_with_causes` walks the chain, and the six sites that report a parse failure to the user now use it: the Graph client, which covers every response the CLI deserializes, and the five token-exchange paths across the three login flows. The same message now reads `... : invalid type: map, expected a string at line 1 column 66`. `keyring.rs` is left alone: it parses with serde_json directly, whose own `Display` already carries the detail. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C736oc7CeNtRZmAJrXm8sG
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FqBTdhSRTBabYv7kkEiUkE
sionsmith
force-pushed
the
fix/graph-error-detail
branch
from
August 29, 2026 17:25
0d14266 to
aac0fe3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A response Graph considers successful but this crate cannot deserialize was
reported as:
That names neither the offending value nor where it sat, so the only way to
investigate one was to capture the response by hand. It is how #69 came to
need a live account to find a one-word type error.
reqwest::Errorkeeps serde's account of the mismatch one level down itssource chain and
Displaynever reaches it.describe_with_causeswalks thechain, and the same failure now reads:
Scope
Six call sites report a parse failure to the user and all six lost it the same
way: the Graph client, which covers every response the CLI deserializes, and
the five token-exchange paths across the three login flows — including both
device-code decoders, which are easy to miss because they call
.json()withthe type on the binding rather than the call.
keyring.rsis left alone: it parses withserde_jsondirectly, whose ownDisplayalready carries the detail.A cause that the outer error already quotes in full is not appended twice,
which is the common shape of a hand-written wrapper such as
write!(f, "reading config: {}", self.0).Not done
serde_path_to_errorwould name the field path rather than a byte offset.That is a dependency added for error text alone, and the type mismatch plus
the offset is already enough to act on.
Tests
A wiremock test drives a Graph-shaped mismatch through
GraphClient::getandasserts the message carries serde's objection. A second drives a malformed
token response through
refresh_access_token, so the auth paths are coveredby more than the client test. Reverting either call site fails its own test.
Two unit tests cover the chain walk itself, including the no-duplication case.
Fixes #79
🤖 Generated with Claude Code
https://claude.ai/code/session_01C736oc7CeNtRZmAJrXm8sG