nautechsystems/nautilus_trader · error · anyhow::Error

{e}

Error message

{e}

What it means

get_tx queries the tx service by hash and converts the returned raw tx bytes back into a typed Tx via Tx::try_from; the bare `{e}` wraps any conversion failure. The lookup itself succeeded but the on-chain tx bytes could not be decoded into the local Tx type, usually due to proto schema mismatch.

Source

Thrown at crates/adapters/dydx/src/grpc/client.rs:516

            ))
        }
    }

    /// Query transaction by hash.
    ///
    /// # Errors
    ///
    /// Returns an error if the query fails.
    pub async fn get_tx(&mut self, hash: &str) -> Result<Tx, anyhow::Error> {
        let req = GetTxRequest {
            hash: hash.to_string(),
        };
        let response = self.tx.get_tx(req).await?.into_inner();

        if let Some(tx) = response.tx {
            // Convert through bytes since the types are incompatible
            let tx_bytes = tx.encode_to_vec();
            Tx::try_from(tx_bytes.as_slice()).map_err(|e| anyhow::anyhow!("{e}"))
        } else {
            anyhow::bail!("Transaction not found")
        }
    }
}

#[cfg(test)]
mod tests {
    use rstest::rstest;

    use super::*;

    #[rstest]
    fn test_height_ordering() {
        let h1 = Height(100);
        let h2 = Height(200);
        assert!(h1 < h2);
        assert_eq!(h1, Height(100));

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the inner error to identify which field/type failed conversion and update proto crates accordingly.
  2. Align ibc-proto/cosmos-sdk-proto versions with those used to broadcast the tx.
  3. If only the hash/result is needed, use the raw response fields instead of full Tx conversion.
  4. Skip unsupported extension_option fields or strip them before decoding when feasible.

Example fix

// before
Tx::try_from(tx_bytes.as_slice()).map_err(|e| anyhow::anyhow!("{e}"))
// after: add context for diagnosability
Tx::try_from(tx_bytes.as_slice())
    .map_err(|e| anyhow::anyhow!("Failed to decode tx {} from chain response: {e}", hex::encode(hash)))
Defensive patterns

Strategy: try-catch

Try / catch

match client.get_tx(&hash).await {
    Ok(tx) => Ok(tx),
    Err(e) if e.to_string().contains("decode") || e.to_string().contains("Unknown") => {
        // schema mismatch: log and degrade to raw response handling
        tracing::warn!("tx decode failed for {hash}: {e:#}");
        Err(e)
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Calling get_tx for a hash whose stored tx contains message types or field versions the local Tx type cannot decode (e.g. txs created by a newer client or with extension options).

Common situations: Fetching a tx created by a different client version with mismatched proto definitions; txs containing extension/non-standard options; ibc-proto/cosmos-sdk version skew between writer and reader.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


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