diff --git a/Cargo.lock b/Cargo.lock
index 65ea3603..3544b394 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -716,6 +716,7 @@ dependencies = [
"reqwest",
"serde",
"serde_json",
+ "serde_path_to_error",
"tokio",
"url",
]
@@ -1433,6 +1434,17 @@ dependencies = [
"zmij",
]
+[[package]]
+name = "serde_path_to_error"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457"
+dependencies = [
+ "itoa",
+ "serde",
+ "serde_core",
+]
+
[[package]]
name = "serde_spanned"
version = "1.1.1"
diff --git a/Cargo.toml b/Cargo.toml
index 8d475e9c..eeb9439a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -22,6 +22,7 @@ pyo3-stub-gen = { version = "0.23", default-features = false, features = ["infer
reqwest = { version = "0.13.4", default-features = false }
serde = { version = "1.0.229", features = ["derive"] }
serde_json = { version = "1.0.149", features = ["arbitrary_precision"] }
+serde_path_to_error = "0.1.20"
syn = { version = "2.0", features = ["full", "extra-traits"] }
thiserror = "2.0"
tokio = { version = "1.52.3", features = ["io-util", "macros", "net", "rt-multi-thread", "time"] }
diff --git a/crates/fmp-py/README.md b/crates/fmp-py/README.md
index da73e226..74fac430 100644
--- a/crates/fmp-py/README.md
+++ b/crates/fmp-py/README.md
@@ -142,12 +142,12 @@ package root):
| Exception | Raised when |
|-----------|-------------|
-| `FmpError` | base class; carries `category`, `endpoint`, `status`, `body`, `body_truncated` |
+| `FmpError` | base class; carries `category`, `endpoint`, `status`, `body`, `body_truncated`, `decode_path`, `decode_kind` |
| `FmpConfigError` | the client cannot be built (missing key, bad URL, insecure auth) |
| `FmpValidationError` | an argument is rejected before the request |
| `FmpTransportError` | the request never produced a response |
| `FmpStatusError` | the provider answered with a non-success status |
-| `FmpDecodeError` | the body could not be decoded into the documented shape |
+| `FmpDecodeError` | the body could not be decoded into the documented shape; `decode_path` names the member (for example `[37].beta`) and `decode_kind` the reason, never the value |
```python
from fmp import FmpClient
diff --git a/crates/fmp-py/python/fmp/_native/errors/__init__.pyi b/crates/fmp-py/python/fmp/_native/errors/__init__.pyi
index 0d6e47b5..d7e50af1 100644
--- a/crates/fmp-py/python/fmp/_native/errors/__init__.pyi
+++ b/crates/fmp-py/python/fmp/_native/errors/__init__.pyi
@@ -64,6 +64,18 @@ class FmpError(builtins.Exception):
Whether `body` was cut short to stay within the excerpt bound.
"""
+ @property
+ def decode_path(self) -> typing.Optional[builtins.str]:
+ r"""
+ Where a JSON response failed to decode, for example `"[37].beta"`; never the member value.
+ """
+
+ @property
+ def decode_kind(self) -> typing.Optional[builtins.str]:
+ r"""
+ Why a JSON response failed to decode: `"syntax"`, `"null"`, `"missing_member"`, `"wrong_type"`, or `"invalid_value"`.
+ """
+
class FmpStatusError(FmpError):
r"""
diff --git a/crates/fmp-py/src/errors.rs b/crates/fmp-py/src/errors.rs
index 098a8f35..c16b542d 100644
--- a/crates/fmp-py/src/errors.rs
+++ b/crates/fmp-py/src/errors.rs
@@ -64,6 +64,20 @@ static ERROR_ATTRIBUTES: &[MemberInfo] = &[
default: None,
deprecated: None,
},
+ MemberInfo {
+ name: "decode_path",
+ r#type: