nautechsystems/nautilus_trader · error

Failed to serialize SignDoc: {e}

Error message

Failed to serialize SignDoc: {e}

What it means

Signing failure in the dYdX credential's sign: serializing the SignDoc to the canonical bytes to be signed failed, so no signature could be produced; the serialization error is embedded in the message.

Source

Thrown at crates/adapters/dydx/src/common/credential.rs:199

    /// Returns an error if the address cannot be parsed as a valid account ID.
    pub fn account_id(&self) -> anyhow::Result<AccountId> {
        self.address
            .parse()
            .map_err(|e| anyhow::anyhow!("Failed to parse account ID: {e}"))
    }

    /// Signs a transaction SignDoc.
    ///
    /// This produces the signature bytes that will be included in the transaction.
    ///
    /// # Errors
    ///
    /// Returns an error if SignDoc serialization or signing fails.
    pub fn sign(&self, sign_doc: &SignDoc) -> anyhow::Result<Vec<u8>> {
        let sign_bytes = sign_doc
            .clone()
            .into_bytes()
            .map_err(|e| anyhow::anyhow!("Failed to serialize SignDoc: {e}"))?;

        let signature = self
            .signing_key
            .sign(&sign_bytes)
            .map_err(|e| anyhow::anyhow!("Failed to sign: {e}"))?;
        Ok(signature.to_bytes().to_vec())
    }

    /// Signs raw message bytes.
    ///
    /// Used for custom signing operations outside of standard transaction flow.
    ///
    /// # Errors
    ///
    /// Returns an error if signing fails.
    pub fn sign_bytes(&self, message: &[u8]) -> anyhow::Result<Vec<u8>> {
        let signature = self
            .signing_key

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the SignDoc fields (chain_id, account_number, account_sequence, messages) are populated and valid before signing
  2. Build SignDoc through the library's tx-building helpers rather than hand-assembling fields
  3. Check dydx proto dependency versions for schema compatibility

Example fix

// before
let sign_doc = SignDoc { /* partially filled */ };
let sig = creds.sign(&sign_doc)?;
// after
let sign_doc = SignDocBuilder::new()
    .chain_id("dydx-mainnet-1")
    .account_number(acct)
    .account_sequence(seq)
    .messages(vec![msg])
    .build()?;
let sig = creds.sign(&sign_doc)?;
Defensive patterns

Strategy: validation

Validate before calling

assert!(!sign_doc.chain_id.is_empty(), "chain_id required");
assert!(!sign_doc.messages.is_empty(), "at least one message required");

Try / catch

let sig = creds.sign(&sign_doc).map_err(|e| { eprintln!("SignDoc serialization failed — verify chain_id, account_number and messages"); e })?;

Prevention

When it happens

Trigger: Calling sign(&SignDoc) where the SignDoc cannot be encoded — e.g. a SignDoc built with malformed/empty fields that the protobuf encoder rejects, or a messages/body combination that fails encoding.

Common situations: Constructing SignDoc manually with missing account number, chain-id, or malformed tx messages; protobuf schema mismatch after upgrading the dydx proto crate.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


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