nautechsystems/nautilus_trader · critical · anyhow::Error
Signer private key in '{}' is not a valid hex private key
Error message
Signer private key in '{}' is not a valid hex private key What it means
During connect (client.rs:2781) the value read from the signer environment variable is parsed with PrivateKeySigner::from_str after trimming whitespace; this error means it is not a valid 32-byte hex private key. The value is never logged, only the variable name is reported.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:2783
// Verify the RPC chain ID against configuration before any signature
let expected_chain_id = u64::from(self.chain.chain_id);
let actual_chain_id = self.http_rpc_client.chain_id().await?;
if actual_chain_id != expected_chain_id {
anyhow::bail!(
"Chain ID mismatch at connect: expected {expected_chain_id}, node reported {actual_chain_id}"
);
}
// Load the signer key from the configured environment variable; the key is never
// logged, serialized, or stored in configuration
let private_key = std::env::var(&self.config.signer_private_key_env).map_err(|_| {
anyhow::anyhow!(
"Signer private key environment variable '{}' is not set",
self.config.signer_private_key_env
)
})?;
let signer = PrivateKeySigner::from_str(private_key.trim()).map_err(|_| {
anyhow::anyhow!(
"Signer private key in '{}' is not a valid hex private key",
self.config.signer_private_key_env
)
})?;
if signer.address() != self.wallet_address {
anyhow::bail!(
"Signer address {} derived from '{}' does not match configured wallet address {}",
signer.address(),
self.config.signer_private_key_env,
self.wallet_address
);
}
self.signer = Some(signer);
if self.cache.has_database()
&& let Err(e) = self.reconcile_unresolved_execution().awaitView on GitHub (pinned to 2114cf6f76)
Solutions
- Regenerate the export so the variable holds exactly 64 hex characters, with or without 0x, and no quotes/whitespace.
- Verify length and charset: echo -n "$VAR" | wc -c should be 64 (or 66 with 0x).
- Confirm the derived address matches the configured wallet before restart (the next check enforces this).
- Never log the key itself while debugging; log only its length and a checksum of it.
Example fix
# before (invalid) export SIGNER_KEY=0xdeadbeef # too short, not 32 bytes # .env loader kept the value wrapped in quotes # after export SIGNER_KEY=0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318
Defensive patterns
Strategy: validation
Validate before calling
let raw = std::env::var(env_name)?.trim().to_string();
let hex = raw.strip_prefix("0x").unwrap_or(&raw);
if hex.len() != 64 || !hex.chars().all(|c| c.is_ascii_hexdigit()) {
anyhow::bail!("signer key in '{env_name}' must be 64 hex chars (32 bytes)");
} Type guard
fn is_valid_private_key_string(s: &str) -> bool {
let h = s.trim().strip_prefix("0x").unwrap_or(s.trim());
h.len() == 64 && h.chars().all(|c| c.is_ascii_hexdigit())
} Try / catch
Fail startup with a message naming only the variable (never the value); point the operator at length/charset requirements.
Prevention
- Validate key format at deployment time, before the node starts.
- Store secrets raw (no extra quoting) and beware .env loaders that preserve quotes.
When it happens
Trigger: The value is not exactly 64 hex characters (32 bytes) after the optional 0x prefix: wrong length, non-hex characters, base64 or decimal encoding, surrounding quotes from a .env file, or a placeholder string like 'changeme'.
Common situations: Copy-pasting a key with a trailing newline hidden in quotes; exporting an encrypted keystore JSON instead of the raw key; a secret-manager template that wraps values in quotes; truncated keys.
Related errors
- Signer private key environment variable '{}' is not set
- Signer address {} derived from '{}' does not match configure
- height must be positive, was {self.height}
- pandas is required for report generation; install it with `p
- {name} must not be None
AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21).
Data as JSON: /api/errors/0d1729426685a568.
Report an issue: GitHub.