{"record":{"id":"b7b90fe42e666ebf","repo":"nautechsystems/nautilus_trader","slug":"failed-to-parse-method-result-hex-string-e","errorCode":null,"errorMessage":"Failed to parse {method} result '{hex_string}': {e}","messagePattern":"Failed to parse (.+?) result '(.+?)': (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/rpc/http.rs","lineNumber":1031,"sourceCode":"\n/// Classifies a broadcast transport failure: a timeout after sending reconciles through the\n/// persisted record. Any other transport failure is treated as ambiguous-after-send too, even\n/// though some (for example connection refused) may never have reached the node; the HTTP\n/// client does not expose the connect-phase distinction, so the conservative outcome never\n/// risks a rebroadcast. Sanitized to never carry the endpoint URL or request payload.\nfn classify_broadcast_transport_error(error: &HttpClientError) -> BroadcastError {\n    match error {\n        HttpClientError::TimeoutError(_) => BroadcastError::TimeoutAfterSend,\n        _ => BroadcastError::Failed(\"transport error\".to_string()),\n    }\n}\n\n/// Parses a required hex-quantity JSON-RPC result, erroring on a missing result.\nfn parse_hex_quantity_result(method: &str, result: Option<String>) -> anyhow::Result<u128> {\n    let hex_string = result.ok_or_else(|| anyhow::anyhow!(\"{method} returned no result\"))?;\n    let stripped = hex_string.strip_prefix(\"0x\").unwrap_or(&hex_string);\n    u128::from_str_radix(stripped, 16)\n        .map_err(|e| anyhow::anyhow!(\"Failed to parse {method} result '{hex_string}': {e}\"))\n}\n\n#[cfg(test)]\npub(crate) mod tests {\n    use alloy::primitives::{address, b256};\n    use rstest::rstest;\n\n    use super::*;\n\n    #[rstest]\n    fn rpc_response_preview_truncates_on_utf8_boundary() {\n        let raw = format!(\"{}é\", \"a\".repeat(499));\n\n        let preview = rpc_response_preview(&raw);\n\n        assert_eq!(\n            preview,\n            format!(\"{}... (truncated, 501 bytes total)\", \"a\".repeat(499))","sourceCodeStart":1013,"sourceCodeEnd":1049,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/rpc/http.rs#L1013-L1049","documentation":"Thrown by `parse_hex_quantity_result` when the JSON-RPC result string exists but is not a valid hex quantity parseable by `u128::from_str_radix` after stripping the `0x` prefix. This protects callers from silently treating malformed node data as a numeric quantity.","triggerScenarios":"A method like eth_chainId/eth_getTransactionCount/eth_estimateGas/eth_maxPriorityFeePerGas returning a non-hex-quantity string — e.g. a decimal string, a 0x-prefixed value exceeding u128, an empty string, or garbage text — reaching `u128::from_str_radix`.","commonSituations":"Non-EVM or misbehaving mock/proxy servers that return decimal numbers as strings; quantity fields exceeding u128 range (rare but possible for some values); provider returning error text inside `result` instead of `error`.","solutions":["Log/inspect the raw result string to see what the node actually returned.","Point the client at a spec-compliant EVM node; verify with curl that eth_chainId returns e.g. \"0x1\".","If values may exceed u128 in your chain, this adapter's u128 bound is exceeded — use a node whose quantities fit or handle the value upstream.","Add a fallback endpoint that returns well-formed hex quantities."],"exampleFix":"// before\n// mock server returns {\"result\": \"1\"} (decimal) -> parse fails\n// after\n// mock server returns {\"result\": \"0x1\"} (hex quantity)","handlingStrategy":"validation","validationCode":"fn is_hex_quantity(s: &str) -> bool {\n    let body = s.strip_prefix(\"0x\").unwrap_or(s);\n    !body.is_empty() && body.chars().all(|c| c.is_ascii_hexdigit())\n        && body.parse::<u128>().map_err(|_| u128::from_str_radix(body, 16).is_ok())\n        && u128::from_str_radix(body, 16).is_ok()\n}\n// validate the raw result string before passing it downstream","typeGuard":"fn as_hex_quantity(v: &serde_json::Value) -> Option<u128> {\n    let s = v.as_str()?;\n    let body = s.strip_prefix(\"0x\").unwrap_or(s);\n    u128::from_str_radix(body, 16).ok()\n}","tryCatchPattern":"match client.chain_id() {\n    Err(e) if e.to_string().starts_with(\"Failed to parse eth_chainId result\") => {\n        tracing::error!(\"non-compliant node returned a non-hex quantity; audit endpoint\");\n        Err(e)\n    }\n    other => other,\n}","preventionTips":["Test mock/proxy servers against spec-compliant responses (hex quantities like \"0x1\", not \"1\").","Curl eth_chainId when integrating a new node to confirm hex-quantity formatting.","Be aware the adapter parses into u128; reject chains whose quantities can exceed it."],"tags":["rpc","hex","parsing"],"backgroundTag":"invalid-argument-format","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}