nautechsystems/nautilus_trader · error

Failed to parse hex quantity '{s}': {e}

Error message

Failed to parse hex quantity '{s}': {e}

What it means

parse_hex_quantity converts a hex quantity string (EVM 'QUANTITY' encoding, e.g. "0x1a") into a u128. It strips an optional 0x prefix and parses with u128::from_str_radix; any parse failure (bad characters, empty string, value exceeding u128) is wrapped in this error including the original string and the inner ParseIntError.

Source

Thrown at crates/adapters/blockchain/src/rpc/types.rs:263

fn deserialize_hex_bool<'de, D>(deserializer: D) -> Result<bool, D::Error>
where
    D: serde::Deserializer<'de>,
{
    let s = String::deserialize(deserializer)?;
    match s.as_str() {
        "0x0" => Ok(false),
        "0x1" => Ok(true),
        _ => Err(serde::de::Error::custom(
            "invalid transaction receipt status; expected 0x0 or 0x1",
        )),
    }
}

fn parse_hex_quantity(s: &str) -> anyhow::Result<u128> {
    let stripped = s.strip_prefix("0x").unwrap_or(s);
    u128::from_str_radix(stripped, 16)
        .map_err(|e| anyhow::anyhow!("Failed to parse hex quantity '{s}': {e}"))
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the '{s}' value in the message; confirm it is a clean hex string (optional 0x prefix, only [0-9a-fA-F]).
  2. If the source sends decimals or JSON numbers, convert to hex upstream or wrap the field with a tolerant deserializer before it reaches these functions.
  3. For tag values like 'latest'/'pending', resolve them to a quantity first or use a tag-aware deserializer; this parser only accepts numeric hex.
  4. If the message shows an overflow-style ParseIntError for a valid hex string, the value exceeds the target width (u64/u8/u128); use the wider deserializer variant.

Example fix

// before (server sends decimal string)
{"blockNumber": "12345"}
// after (EVM hex quantity)
{"blockNumber": "0x3039"}
Defensive patterns

Strategy: validation

Validate before calling

fn is_hex_quantity(s: &str) -> bool {
    let h = s.strip_prefix("0x").unwrap_or(s);
    !h.is_empty() && h.chars().all(|c| c.is_ascii_hexdigit()) && h.chars().count() <= 32
}

Try / catch

match parse_hex_quantity(field) {
    Ok(v) => { /* use v */ }
    Err(e) => { eprintln!("bad quantity field: {e}"); /* treat as null/default */ }
}

Prevention

When it happens

Trigger: Any deserialize_hex_u64/deserialize_hex_u64_opt/deserialize_hex_u8_opt/deserialize_hex_u128_opt invocation (serde field deserialization of RPC JSON responses) where the field is not a valid hex quantity: contains non-hex characters, is an empty string, uses decimal notation, or the value overflows the target type after conversion.

Common situations: An RPC node returns a decimal string or JSON number instead of a 0x-prefixed hex quantity; a field contains '0x' alone or 'pending'/'latest' tags passed to a quantity field; upstream API changed response format after a version update; value too large for u64/u8 target after a successful u128 parse.

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.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/58d3e22c6990622d. Report an issue: GitHub.