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().await

View on GitHub (pinned to 2114cf6f76)

Solutions

  1. Regenerate the export so the variable holds exactly 64 hex characters, with or without 0x, and no quotes/whitespace.
  2. Verify length and charset: echo -n "$VAR" | wc -c should be 64 (or 66 with 0x).
  3. Confirm the derived address matches the configured wallet before restart (the next check enforces this).
  4. 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

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


AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21). Data as JSON: /api/errors/0d1729426685a568. Report an issue: GitHub.