{"record":{"id":"ef648153cc44e382","repo":"nautechsystems/nautilus_trader","slug":"cannot-create-sign-doc-e","errorCode":null,"errorMessage":"Cannot create sign doc: {e}","messagePattern":"Cannot create sign doc: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/dydx/src/grpc/builder.rs","lineNumber":164,"sourceCode":"            let ext = TxExtension {\n                selected_authenticators: auth_ids.to_vec(),\n            };\n            builder.non_critical_extension_option(ext.to_any());\n        }\n\n        let tx_body = builder.finish();\n\n        let fee = fee.unwrap_or_else(|| {\n            self.calculate_fee(None)\n                .unwrap_or_else(|_| Self::default_fee())\n        });\n\n        let auth_info =\n            SignerInfo::single_direct(Some(account.public_key()), account.sequence_number)\n                .auth_info(fee);\n\n        let sign_doc = SignDoc::new(&tx_body, &auth_info, &self.chain_id, account.account_number)\n            .map_err(|e| anyhow::anyhow!(\"Cannot create sign doc: {e}\"))?;\n\n        account.sign(sign_doc)\n    }\n\n    /// Build and simulate a transaction to estimate gas.\n    ///\n    /// Returns the raw transaction bytes suitable for simulation.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if transaction building fails.\n    pub fn build_for_simulation(\n        &self,\n        account: &Account,\n        msgs: impl IntoIterator<Item = Any>,\n    ) -> Result<Vec<u8>, anyhow::Error> {\n        let tx_raw = self.build_transaction(account, msgs, None, None)?;\n        tx_raw.to_bytes().map_err(|e| anyhow::anyhow!(\"{e}\"))","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/dydx/src/grpc/builder.rs#L146-L182","documentation":"TxBuilder::build_transaction wraps the cosmos-sdk SignDoc::new failure with this message. SignDoc construction serializes the tx body, auth info, chain id, and account number into the canonical bytes that will be signed; it fails if those values cannot be encoded consistently. The anyhow context preserves the underlying prost/encoding error.","triggerScenarios":"Calling build_transaction (directly or via build_for_simulation) when SignDoc::new fails to serialize the tx body/auth_info for the given chain_id and account_number — typically malformed tx messages, oversized payloads, or a protobuf encoding failure.","commonSituations":"A message list containing a proto message whose serialization exceeds limits; mismatched or malformed chain-id string; account sequence/number values that break encoding after a node reset or mismatch between local account state and chain state.","solutions":["Log/print the inner `{e}` to see the underlying protobuf encoding error and fix the offending message in msgs.","Verify the chain_id matches the target network (dydx-mainnet-1 vs dydx-dymension-testnet-3 etc.) and the account_number/sequence come from a fresh query_account.","Reduce message size or split messages into multiple transactions if the tx body exceeds size limits.","Check that prost/ibc-proto dependency versions align so the tx body and auth_info types serialize with the same schema."],"exampleFix":"// before\nlet sign_doc = SignDoc::new(&tx_body, &auth_info, &self.chain_id, account.account_number)\n    .map_err(|e| anyhow::anyhow!(\"Cannot create sign doc: {e}\"))?;\n// after: validate inputs before signing\nif msgs.is_empty() { anyhow::bail!(\"No messages to include in tx\"); }\nlet sign_doc = SignDoc::new(&tx_body, &auth_info, &self.chain_id, account.account_number)\n    .map_err(|e| anyhow::anyhow!(\"Cannot create sign doc (chain_id={chain_id}): {e}\"))?;","handlingStrategy":"try-catch","validationCode":"if msgs.is_empty() { return Err(anyhow!(\"no messages provided\")); }","typeGuard":null,"tryCatchPattern":"match builder.build_transaction(&account, msgs, fee, memo) {\n    Ok(tx) => tx,\n    Err(e) if e.to_string().starts_with(\"Cannot create sign doc\") => {\n        // refresh account state and retry once\n        let (num, seq) = client.query_address(addr).await?;\n        builder.build_transaction(&refreshed_account, msgs, fee, memo)\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Refresh account_number/sequence from chain before every sign","Keep proto/prost crate versions consistent","Validate the message list is non-empty and well-formed before building"],"tags":["grpc","cosmos","signing","serialization"],"backgroundTag":"protobuf-marshal-failed","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}