nautechsystems/nautilus_trader · critical

Verified chain ID does not match the transaction chain

Error message

Verified chain ID does not match the transaction chain

What it means

Before signing, the client re-verifies the chain ID via its verification provider and requires it to equal the transaction's expected chain ID. A mismatch means the node/wallet context the transaction targets differs from the verified chain, so signing is refused to prevent replay or cross-chain mistakes.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:2295

    )]
    async fn prepare_and_sign_with_anchors(
        &self,
        intent_id: i64,
        created_block: u64,
        to: Address,
        value: U256,
        input: Bytes,
        swap_anchors: Option<&SwapQuoteAnchors>,
        authorization: Option<&TransactionAuthorization>,
        decision_header: Option<Verified<VerifiedBlockHeader>>,
    ) -> anyhow::Result<PreparedTransaction> {
        let expected_chain_id = u64::from(self.chain_id);
        let chain_id_verification = required_verification(
            self.verification.verify_chain_id().await,
            "pre-sign chain ID",
        )?;
        let actual_chain_id = chain_id_verification.value;
        anyhow::ensure!(
            actual_chain_id == expected_chain_id,
            "Verified chain ID does not match the transaction chain"
        );
        let decision_header_verification = if let Some(anchors) = swap_anchors {
            required_verification(
                self.verification.verify_block(anchors.state.number).await,
                "pre-sign swap decision header reread",
            )?
        } else {
            match decision_header {
                Some(verified) => verified,
                None => {
                    let now_unix_secs = current_unix_secs()?;
                    required_verification(
                        self.verification
                            .verify_decision_header(now_unix_secs)
                            .await,
                        "pre-sign decision header",

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Align the client's configured chain_id with the network actually served by the configured RPC endpoint.
  2. Check the RPC URL — switch to a node on the intended chain.
  3. Verify no automatic provider failover silently switched chains; pin the endpoint.
  4. Re-verify `self.chain_id` matches the signer/wallet network and reinitialize the client if config changed.

Example fix

// before: client on testnet RPC but chain_id set to mainnet
// chain_id: 1, rpc: https://sepolia.infura.io
let client = ExecutionClient::new(chain_id=1, rpc=SEPOLIA_URL)?;
// after
let client = ExecutionClient::new(chain_id=11155111, rpc=SEPOLIA_URL)?;
Defensive patterns

Strategy: validation

Validate before calling

let node_chain_id = provider.get_chain_id().await?;
assert_eq!(node_chain_id, client.chain_id(), "RPC chain mismatch with client config");

Try / catch

match result { Err(e) if e.to_string().contains("Verified chain ID does not match") => { fail_fast_and_reconfigure_rpc(e); } Ok(v) => v }

Prevention

When it happens

Trigger: During the pre-sign check, `verification.verify_chain_id()` returns a chain ID different from `self.chain_id` (u64) used for the transaction — e.g. the RPC endpoint serves a different network than configured.

Common situations: RPC URL points to mainnet while client configured for a testnet (or vice versa); provider failover switched to a node on another chain; chain_id config value stale after a fork or network rename.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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