nautechsystems/nautilus_trader · error
EIP-712 signing failed: {e}
Error message
EIP-712 signing failed: {e} What it means
build_and_sign assembles the Polymarket order and then signs it with the EIP-712 order signer via order_signer.sign_order. Any failure from the signer (invalid private key, wallet/secp256k1 errors, malformed signing payload) is wrapped as "EIP-712 signing failed: {e}".
Source
Thrown at crates/adapters/polymarket/src/execution/order_builder.rs:429
salt,
maker: self.maker_address.clone(),
signer: self.order_signer_address(),
token_id: Ustr::from(token_id),
maker_amount,
taker_amount,
side,
signature_type: self.signature_type,
expiration: expiration.to_string(),
timestamp: timestamp_ms.to_string(),
metadata: ZERO_BYTES32.to_string(),
builder: POLYMARKET_NAUTILUS_BUILDER_CODE.to_string(),
signature: SecretString::default(),
};
let signature = self
.order_signer
.sign_order(&poly_order, neg_risk)
.map_err(|e| anyhow::anyhow!("EIP-712 signing failed: {e}"))?;
poly_order.signature = SecretString::from(signature);
Ok(poly_order)
}
fn order_signer_address(&self) -> String {
match self.signature_type {
SignatureType::Poly1271 => self.maker_address.clone(),
_ => self.signer_address.clone(),
}
}
}
fn validation_failed(detail: impl Into<String>) -> OrderDeniedReason {
OrderDeniedReason::ValidationFailed {
detail: detail.into(),
}
}View on GitHub (pinned to 18893faf8b)
Solutions
- Inspect the wrapped {e} message; it distinguishes key-decoding failures from payload-encoding failures.
- Verify the signing private key is a valid 32-byte hex secret and matches the maker/signer address configured on the builder.
- Confirm environment/config supplies the key (e.g. private key env var set and not a placeholder) before initializing the execution client.
Example fix
// before POLYMARKET_PRIVATE_KEY="changeme" // invalid hex -> signing fails // after POLYMARKET_PRIVATE_KEY="0x<64 hex chars>" // valid secp256k1 key matching maker address
Defensive patterns
Strategy: validation
Validate before calling
let key = std::env::var("POLYMARKET_PRIVATE_KEY")?;
let key = key.trim_start_matches("0x");
hex::decode(key).map_err(|e| format!("invalid private key hex: {e}"))?;
if key.len() != 64 { return Err("private key must be 64 hex chars".into()); } Type guard
fn is_valid_private_key(s: &str) -> bool {
let s = s.trim_start_matches("0x");
s.len() == 64 && s.chars().all(|c| c.is_ascii_hexdigit())
} Try / catch
let signed = match builder.build_limit_order(&order, ...) {
Ok(o) => o,
Err(e) if e.to_string().contains("EIP-712 signing failed") => {
tracing::error!("signing failed, check wallet key/config: {e:#}");
return Err(e);
}
Err(e) => return Err(e),
}; Prevention
- Validate the private key (hex, 32 bytes, matches maker address) at client startup, not at first order.
- Keep key material in a secret store, not inline config.
- Test signing once during initialization with a dry-run payload.
When it happens
Trigger: Calling build_limit_order, build_limit_order_from_collateral, or build_market_order when the configured private key is invalid/empty, the key cannot produce a secp256k1 signature, or the order payload encoding fails inside sign_order.
Common situations: Missing or malformed POLYMARKET private key in env/config (wrong length, not hex, placeholder value); key does not match the configured maker/signer address; dependency or chain-id mismatch producing an unencodable payload.
Related errors
- Failed to derive order hash: {e}
- Polymarket {signature_type:?} signature type requires a fund
- Failed to build market order: {e}
- signature_hex called before sign
- unmapped_in_scope_message("open order", instrument_id, Some(
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/598fa4164fd266c1.
Report an issue: GitHub.