nautechsystems/nautilus_trader · error

Invalid contract address length: expected {} bytes, was {}

Error message

Invalid contract address length: expected {} bytes, was {}

What it means

This error means the decoded address bytes from the RpcLog's address field did not have exactly 20 bytes (Address::len_bytes()), the canonical Ethereum address length. extract_address decodes the hex and enforces the length before constructing the Address, rejecting truncated, padded, or over-long values rather than truncating silently.

Source

Thrown at crates/adapters/blockchain/src/rpc/log.rs:110

/// # Errors
///
/// Returns an error if the log index is missing or cannot be parsed.
pub fn extract_log_index(log: &RpcLog) -> anyhow::Result<u32> {
    let hex = log
        .log_index
        .as_ref()
        .ok_or_else(|| anyhow::anyhow!("Missing log index"))?;
    parse_hex_u32(hex)
}

/// Extract contract address from RPC log.
///
/// # Errors
///
/// Returns an error if the address is invalid.
pub fn extract_address(log: &RpcLog) -> anyhow::Result<Address> {
    let bytes = decode_hex(&log.address)?;
    anyhow::ensure!(
        bytes.len() == Address::len_bytes(),
        "Invalid contract address length: expected {} bytes, was {}",
        Address::len_bytes(),
        bytes.len()
    );
    Ok(Address::from_slice(&bytes))
}

/// Extract topic bytes at index.
///
/// # Errors
///
/// Returns an error if the topic at the specified index is missing.
pub fn extract_topic_bytes(log: &RpcLog, index: usize) -> anyhow::Result<Vec<u8>> {
    let hex = log
        .topics
        .get(index)
        .ok_or_else(|| anyhow::anyhow!("Missing topic at index {index}"))?;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Log the raw address string and confirm it decodes to exactly 40 hex characters (20 bytes).
  2. If the provider returns a different encoding, normalize it to 20-byte form before calling extract_address.
  3. Check you are reading log.address and not a topic or data field.
  4. Reject or quarantine logs with malformed addresses instead of unwrapping.

Example fix

// before
let addr = extract_address(&log)?;
// after
let raw = decode_hex(&log.address)?;
if raw.len() != 20 {
    eprintln!("skipping log with malformed address: {:?}", log.address);
    return Ok(None);
}
let addr = extract_address(&log)?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_address_hex(s: &str) -> bool {
    decode_hex(s).map(|b| b.len() == 20).unwrap_or(false)
}

Type guard

fn is_valid_address(log: &RpcLog) -> bool {
    decode_hex(&log.address).map_or(false, |b| b.len() == Address::len_bytes())
}

Try / catch

match extract_address(&log) {
    Ok(a) => a,
    Err(e) => { log::warn!("bad address {:?}: {e}", log.address); return Ok(None); }
}

Prevention

When it happens

Trigger: Calling extract_address on a log whose address field decodes to fewer or more than 20 bytes — e.g. an empty string, a checksummed string with characters the hex decoder rejects, or a nonstandard provider returning full-width or partial addresses.

Common situations: Nonstandard or L2-sidecar RPCs returning addresses in unexpected encodings, accidentally passing a topic (32 bytes) as the address, or malformed/offline test fixtures.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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