nautechsystems/nautilus_trader · error
Failed to parse eth_getStorageAt response
Error message
Failed to parse eth_getStorageAt response
What it means
After a successful `eth_getStorageAt` call, the returned string is parsed into a `B256` (32-byte fixed hash). If the string is not valid hex of appropriate length, this error is raised (note: the original parse error is discarded, only a static message is returned).
Source
Thrown at crates/adapters/blockchain/src/rpc/http.rs:405
#[allow(
dead_code,
reason = "Used by the independent verification read inventory"
)]
pub(crate) async fn get_storage_at(
&self,
address: &Address,
slot: &B256,
block: u64,
) -> anyhow::Result<B256> {
let result: Option<String> = self
.execute_execution_rpc_call(
"eth_getStorageAt",
serde_json::json!([address, slot, block_parameter(Some(block))]),
)
.await?;
let value = result.ok_or_else(|| anyhow::anyhow!("eth_getStorageAt returned no result"))?;
B256::from_str(&value)
.map_err(|_| anyhow::anyhow!("Failed to parse eth_getStorageAt response"))
}
async fn get_code_with_block(
&self,
address: &Address,
block: Option<u64>,
) -> anyhow::Result<Bytes> {
let result: Option<String> = self
.execute_execution_rpc_call(
"eth_getCode",
serde_json::json!([address, block_parameter(block)]),
)
.await?;
let hex_string = result.ok_or_else(|| anyhow::anyhow!("eth_getCode returned no result"))?;
let stripped = hex_string.strip_prefix("0x").unwrap_or(&hex_string);
let bytes = hex::decode(stripped)
.map_err(|e| anyhow::anyhow!("Failed to decode eth_getCode result: {e}"))?;
Ok(Bytes::from(bytes))View on GitHub (pinned to 18893faf8b)
Solutions
- Verify the node returns a full 32-byte 0x-prefixed hex string for eth_getStorageAt
- Use a compliant node (geth/erigon standard behavior) or update node version
- If values are unpadded, left-pad them to 64 hex chars before parsing
- Log the raw value to confirm its actual format
Example fix
// before: node returns unpadded value -> B256::from_str fails
let value = client.get_storage_at(&addr, slot, Some(block)).await?;
// after: left-pad to 32 bytes when necessary
let raw = format!("0x{:0>64}", raw_hex.trim_start_matches("0x")); Defensive patterns
Strategy: validation
Validate before calling
fn is_b256_hex(s: &str) -> bool {
let body = s.strip_prefix("0x").unwrap_or(s);
body.len() == 64 && body.chars().all(|c| c.is_ascii_hexdigit())
} Prevention
- Use standard node implementations that return 32-byte padded hex
- Sanitize/left-pad storage values when integrating non-standard chains
- Snapshot the raw response when first integrating a new chain
- Keep node software up to date
When it happens
Trigger: Node returns a storage value that is not a 32-byte hex string — e.g. a short hex value without padding (some chains return 0x + fewer bytes), decimal output, or a value with unexpected formatting.
Common situations: Non-standard or modified node implementations (some L2s or private chains) returning unpadded or differently-encoded storage values.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to parse balance hex string '{hex_string}': {e}
- Failed to parse {method} response
- eth_getStorageAt returned no result
- Failed to decode eth_getCode result: {e}
- Finalized block {} does not contain transaction {}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/41332e37132cb735.
Report an issue: GitHub.