diem/diem · error
Signing multi agent txn failed
Error message
Signing multi agent txn failed
What it means
LocalAccount::sign_multi_agent_with_transaction_builder unwraps RawTransaction::sign_multi_agent with a generic 'Signing multi agent txn failed' message. sign_multi_agent validates signer consistency (primary key matches sender, secondary keys match addresses); any mismatch makes it return an error, and this helper turns that into a panic.
Source
Thrown at sdk/src/types.rs:87
.iter()
.map(|signer| signer.address())
.collect();
let secondary_signer_privkeys = secondary_signers
.iter()
.map(|signer| signer.private_key())
.collect();
let raw_txn = builder
.sender(self.address())
.sequence_number(self.sequence_number())
.build();
*self.sequence_number_mut() += 1;
raw_txn
.sign_multi_agent(
self.private_key(),
secondary_signer_addresses,
secondary_signer_privkeys,
)
.expect("Signing multi agent txn failed")
.into_inner()
}
pub fn address(&self) -> AccountAddress {
self.address
}
pub fn private_key(&self) -> &Ed25519PrivateKey {
self.key.private_key()
}
pub fn public_key(&self) -> &Ed25519PublicKey {
self.key.public_key()
}
pub fn authentication_key(&self) -> AuthenticationKey {
self.key.authentication_key()
}View on GitHub (pinned to fc4714a8ea)
Solutions
- Verify every (address, private_key) pair matches: derive the address from each private key and compare
- Confirm the primary signer (self) is actually the transaction sender of the raw_txn
- Check secondary_signer_addresses and secondary_signer_privkeys are the same length and in the same order
- Use RawTransaction::sign_multi_agent directly for fallible handling instead of the expect-based helper
Example fix
// before
let signed = account.sign_multi_agent_with_transaction_builder(builder, secondary_addrs, secondary_keys);
// after
assert_eq!(account.address(), raw_txn.sender(), "primary signer must be sender");
for (a, k) in secondary_addrs.iter().zip(secondary_keys) {
assert_eq!(a, &diem_crypto::PrivateKey::public_key_for(k).into(), "key/address mismatch");
}
let signed = account.sign_multi_agent_with_transaction_builder(builder, secondary_addrs, secondary_keys); Defensive patterns
Strategy: validation
Validate before calling
fn validate_signers(
sender: AccountAddress,
primary: &Ed25519PrivateKey,
secondary: &[(AccountAddress, Ed25519PrivateKey)],
) -> bool {
if AccountAddress::from(Ed25519PublicKey::from(primary)) != sender {
return false;
}
secondary.iter().all(|(addr, key)| {
&AccountAddress::from(Ed25519PublicKey::from(key)) == addr
})
} Try / catch
// prefer the fallible API over the expect-based helper
let signed = raw_txn
.sign_multi_agent(
account.private_key(),
secondary_addrs,
secondary_keys,
)
.map_err(|e| anyhow!("multi-agent signing failed: {}", e))?
.into_inner(); Prevention
- Derive each signer address from its private key rather than passing them as independent inputs
- Keep secondary signer addresses and keys in a single paired structure to prevent ordering bugs
- Assert the primary signer equals the raw transaction sender before signing
When it happens
Trigger: Calling sign_multi_agent_with_transaction_builder where the primary private key does not correspond to the raw transaction's sender, or a secondary private key does not correspond to its paired secondary address.
Common situations: Swapped address/key pairs in the secondary signer arrays; sender address derived from a different key than self; building multi-agent payloads with accounts loaded in the wrong order.
Related errors
- Signing a txn can't fail
- Error: Could not find sender key pair.
- sender must have been set
- sequence number must have been set
- Unable to write key to file at specified path
AI-assisted analysis of diem/diem@fc4714a8ea (2026-09-04).
Data as JSON: /api/errors/801c27e3379dc706.
Report an issue: GitHub.