Repository navigation
feat(sdk): expose decode path and kind on JSON decode failures - #370
Merged
Merged
Conversation
Introduce the `serde_path_to_error` crate as a workspace dependency and wire it into the libfmp crate to support decode path reporting. Refs #366
Synthetic 40-row company-screener fixture whose row 37 carries beta null, for the decode-path acceptance tests (issue 366)
Decode failures on *fmp.Error now locate the offending member without ever exposing its value. The Error struct gains a Path field holding the RFC 6901 JSON pointer of the failing member (such as "/37/beta") and a DecodeKind field giving a coarse, redaction-safe reason for the failure. Path is "" for a failure at the document root and on every non-decode error. DecodeKind mirrors the Rust crate's DecodeErrorKind with the stable lowercase values syntax, null, missing_member, wrong_type, and invalid_value, so the reason stays consistent across the Rust, Python, and Go SDKs. Error formatting now appends the decode kind and path. The client reads only the structured fields of the json/v2 error, never its text, and consults the body to distinguish a JSON null from an absent member. The pointer is passed through the redactor before it reaches the caller, so no member value survives on the error.
Decode JSON responses through serde_path_to_error so failures can report where and why they occurred without leaking the offending value. **Decode diagnostics on Error:** * Added `DecodeErrorKind` in `error.rs`, a coarse, non-exhaustive classification (`syntax`, `null`, `missing_member`, `wrong_type`, `invalid_value`) with a stable lowercase `as_str` for language bindings. * Added `Error::decode_path` and `Error::decode_kind` accessors, plus the internal `with_decode_location` builder, and extended the `Display` output to include the kind description and member path. * The path names members and array indexes only, for example `[37].beta`, and is `None` for root-level and non-JSON failures such as binary bodies. **JSON decoding:** * `decode_json` now deserializes via `serde_path_to_error`, classifies the failure into a `DecodeFailure` carrying the path and kind, and discards the decoder's own message so no member value survives. * The client redacts the decode path before attaching it to the error.
Surface where and why a JSON response failed to decode without leaking the offending member value. `FmpError` now carries two new attributes: `decode_path`, naming the member (for example `[37].beta`), and `decode_kind`, giving the reason (`syntax`, `null`, `missing_member`, `wrong_type`, or `invalid_value`). These attributes let callers locate a decode failure precisely while keeping response contents out of both the message and the error object. Tests confirm the path and kind are reported and that the offending string value never reaches the message, repr, or any attribute. close #366
Extend the decode path test suites across the Python, Rust, and Go SDKs to verify that non-JSON and empty response bodies surface as root-level syntax failures with no decode path. * Python: assert the raised `FmpDecodeError` reports a `syntax` kind and `None` path for a non-JSON body. * Rust: add a case covering both non-JSON and empty bodies as root syntax failures. * Go: add a `not json` case expecting an empty path and `DecodeKindSyntax`.
Clarify that DecodeKind values are stable and that new kinds are only appended, so consumers can rely on existing values not changing.
The Go SDK previously reported a fractional count and other value-level decode failures as a generic wrong-type error, so callers could not tell where in the response the rejected value lived or why it was rejected. **Decode error classification**: * Added `invalidMemberValueError` in `sdk/go/decode.go`, which marks a member whose JSON kind is correct but whose value the Rust decoder rejects, such as a non-integral count. * Tracked the new `memberKind` on the error and surfaced it through the decode path/kind resolution so such members report their own kind instead of defaulting to `DecodeKindWrongType`. **Test coverage**: * Extended the Go, Rust, and Python analyst tests to assert the decode path (`/0/buy`, `[0].buy`), the `InvalidValue` kind, and that the member value is never leaked into the error message.
benbenbang
enabled auto-merge (rebase)
September 29, 2026 03:05
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.
When a JSON response fails to decode, callers previously received a generic error that neither located the offending member nor explained why it was rejected. This made debugging decode failures difficult while offering no safe way to inspect them, since surfacing the raw decoder message risked leaking response values. This change adds structured, redaction-safe decode diagnostics consistently across the Rust, Python, and Go SDKs.
What changed:
Other:
Refs #366