nautechsystems/nautilus_trader · error

Token manifest address is invalid

Error message

Token manifest address is invalid

What it means

Each entry in manifest.tokens must carry a valid 20-byte Ethereum address; the validator parses token.address with alloy's Address::from_str and throws this error when parsing fails. Without a parseable address the token cannot be cross-checked against the pinned contract set.

Source

Thrown at crates/adapters/blockchain/src/rpc/verification.rs:1355

    }

    for required in [
        BlockchainContractRole::Router,
        BlockchainContractRole::Factory,
        BlockchainContractRole::WrappedNative,
        BlockchainContractRole::Quote,
        BlockchainContractRole::Token,
        BlockchainContractRole::Pool,
    ] {
        anyhow::ensure!(
            roles.contains(&required),
            "Deployment manifest is missing a required role"
        );
    }

    for token in &manifest.tokens {
        let address = Address::from_str(&token.address)
            .map_err(|_| anyhow::anyhow!("Token manifest address is invalid"))?;
        anyhow::ensure!(
            contract_addresses.contains(&address),
            "Token manifest address has no contract identity"
        );
        anyhow::ensure!(
            !token.name.trim().is_empty()
                && !token.symbol.trim().is_empty()
                && matches!(token.asset_role.as_str(), "base" | "quote" | "both"),
            "Token manifest identity or asset role is invalid"
        );
    }

    for pool in &manifest.pools {
        for address in [
            &pool.address,
            &pool.token0,
            &pool.token1,
            &pool.factory,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Set token.address to the correct 20-byte hex contract address (0x + 40 hex chars)
  2. Resolve any ENS name to its address off-chain before writing the manifest
  3. Copy the address from the contract entry of the same deployment to keep them consistent

Example fix

// before
{"address": "weth.eth", "name": "WETH"}
// after
{"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "name": "WETH"}
Defensive patterns

Strategy: validation

Validate before calling

fn valid_address(s: &str) -> bool {
    Address::from_str(s).is_ok()
}
assert!(manifest.tokens.iter().all(|t| valid_address(&t.address)));

Try / catch

match validate_manifest(&config) {
    Err(e) if e.to_string().contains("Token manifest address is invalid") => {
        eprintln!("fix the malformed 20-byte hex token address: {e}");
    }
    Err(e) => return Err(e),
    Ok(v) => v,
}

Prevention

When it happens

Trigger: Running manifest verification when a tokens[] entry has an address that is not valid hex-20: empty string, wrong length, non-hex characters, or an EVM-unfriendly value like an ENS name or a Solana/SPL address pasted from another chain's config.

Common situations: Copying token addresses from another network's manifest; ENS names instead of resolved addresses; truncated hex from spreadsheet/CSV round-trips; wrong chain's token contract in a multi-chain config.

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/3aac6860dcf5d68d. Report an issue: GitHub.