nautechsystems/nautilus_trader · error · anyhow::Error

{e}

Error message

{e}

What it means

build_for_simulation serializes the built (signed) RawTx into bytes via tx_raw.to_bytes() and wraps any failure in anyhow with the bare error. This fails when the protobuf encoding of the complete transaction cannot be produced, e.g. invalid nested messages or an internal serialization bug.

Source

Thrown at crates/adapters/dydx/src/grpc/builder.rs:182

            .map_err(|e| anyhow::anyhow!("Cannot create sign doc: {e}"))?;

        account.sign(sign_doc)
    }

    /// Build and simulate a transaction to estimate gas.
    ///
    /// Returns the raw transaction bytes suitable for simulation.
    ///
    /// # Errors
    ///
    /// Returns an error if transaction building fails.
    pub fn build_for_simulation(
        &self,
        account: &Account,
        msgs: impl IntoIterator<Item = Any>,
    ) -> Result<Vec<u8>, anyhow::Error> {
        let tx_raw = self.build_transaction(account, msgs, None, None)?;
        tx_raw.to_bytes().map_err(|e| anyhow::anyhow!("{e}"))
    }
}

impl Debug for TxBuilder {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct(stringify!(TxBuilder))
            .field("chain_id", &self.chain_id)
            .field("fee_denom", &self.fee_denom)
            .finish()
    }
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the propagated error to identify which field failed to encode and correct the corresponding msg.
  2. Rebuild the transaction after refreshing account sequence/number from query_address so the signed doc matches chain state.
  3. Pin consistent versions of the cosmos/prost proto crates so build and encode use identical schemas.
  4. Fall back to a smaller message batch to isolate the offending message.

Example fix

// before
tx_raw.to_bytes().map_err(|e| anyhow::anyhow!("{e}"))
// after: add context for diagnosability
tx_raw.to_bytes().map_err(|e| anyhow::anyhow!("Cannot encode tx to bytes for simulation: {e}"))
Defensive patterns

Strategy: try-catch

Try / catch

let bytes = match builder.build_for_simulation(&account, msgs) {
    Ok(b) => b,
    Err(e) => { tracing::error!("tx encode failed: {e:#}"); return Err(e); }
};

Prevention

When it happens

Trigger: Calling build_for_simulation when tx_raw.to_bytes() fails after build_transaction succeeded — an encoding failure on the finalized signed tx.

Common situations: Simulating a tx built from messages that individually encode but jointly produce an invalid payload; version skew between proto definitions used to build vs encode the tx.

Related errors


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