nautechsystems/nautilus_trader · error

Failed to parse address: {e}

Error message

Failed to parse address: {e}

What it means

`PoolIdentifier::to_address` converts an Address-variant identifier into an `alloy` `Address`. It errors either when called on the `PoolId` variant (a pool ID is not an address) or when the stored string fails checksummed address parsing.

Source

Thrown at crates/model/src/defi/pool_identifier.rs:193

    }

    /// Returns true if this is a `PoolId` variant (V4 pools).
    #[must_use]
    pub fn is_pool_id(&self) -> bool {
        matches!(self, Self::PoolId(_))
    }

    /// Converts to native Address type (V2/V3 pools only).
    ///
    /// Returns the underlying Address for use with alloy/ethers operations.
    ///
    /// # Errors
    ///
    /// Returns error if this is a `PoolId` variant or if parsing fails.
    pub fn to_address(&self) -> anyhow::Result<Address> {
        match self {
            Self::Address(s) => Address::parse_checksummed(s.as_str(), None)
                .map_err(|e| anyhow::anyhow!("Failed to parse address: {e}")),
            Self::PoolId(_) => anyhow::bail!("Cannot convert PoolId variant to Address"),
        }
    }

    /// Converts to native bytes array (V4 pools only).
    ///
    /// Returns the 32-byte pool ID for use in V4-specific operations.
    ///
    /// # Errors
    ///
    /// Returns error if this is an Address variant or if hex decoding fails.
    pub fn to_pool_id_bytes(&self) -> anyhow::Result<[u8; 32]> {
        match self {
            Self::PoolId(s) => {
                let hex_str = s.strip_prefix("0x").unwrap_or(s.as_str());
                hex::decode_array::<32>(hex_str)
                    .map_err(|e| anyhow::anyhow!("Failed to decode pool ID hex: {e}"))
            }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Match on the variant first: only call `to_address()` on `PoolIdentifier::Address`.
  2. For PoolId values use `to_pool_id_bytes()` instead.
  3. Store addresses in checksummed form (EIP-55) or parse with `Address::parse_checksummed(..., None)`/`Address::from_str` appropriately.
  4. Validate the address string with `validate_hex_string` and length 40 before constructing.

Example fix

// before
let addr = identifier.to_address()?; // panics into error for PoolId
// after
let addr = match &identifier {
    PoolIdentifier::Address(_) => identifier.to_address()?,
    PoolIdentifier::PoolId(_) => return Err(anyhow::anyhow!("expected Address variant")),
};
Defensive patterns

Strategy: type-guard

Validate before calling

fn expect_address(id: &PoolIdentifier) -> Option<&Ustr> {
    match id { PoolIdentifier::Address(a) => Some(a), _ => None }
}

Type guard

fn is_address_variant(id: &PoolIdentifier) -> bool {
    matches!(id, PoolIdentifier::Address(_))
}

Try / catch

match identifier.to_address() {
    Ok(addr) => addr,
    Err(e) if e.to_string().contains("PoolId") => fallback_pool_id_path(),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `to_address()` on a `PoolIdentifier::PoolId` value, or on an Address variant whose string is not a valid checksummed 20-byte hex address (wrong length, bad checksum casing, non-hex).

Common situations: Code that lost track of which variant it holds after parsing mixed pool data; addresses stored lowercased without EIP-55 checksums being parsed with `parse_checksummed`.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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