{"record":{"id":"0d1729426685a568","repo":"nautechsystems/nautilus_trader","slug":"signer-private-key-in-is-not-a-valid-hex-priv","errorCode":null,"errorMessage":"Signer private key in '{}' is not a valid hex private key","messagePattern":"Signer private key in '(.+?)' is not a valid hex private key","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":2783,"sourceCode":"        // Verify the RPC chain ID against configuration before any signature\n        let expected_chain_id = u64::from(self.chain.chain_id);\n        let actual_chain_id = self.http_rpc_client.chain_id().await?;\n        if actual_chain_id != expected_chain_id {\n            anyhow::bail!(\n                \"Chain ID mismatch at connect: expected {expected_chain_id}, node reported {actual_chain_id}\"\n            );\n        }\n\n        // Load the signer key from the configured environment variable; the key is never\n        // logged, serialized, or stored in configuration\n        let private_key = std::env::var(&self.config.signer_private_key_env).map_err(|_| {\n            anyhow::anyhow!(\n                \"Signer private key environment variable '{}' is not set\",\n                self.config.signer_private_key_env\n            )\n        })?;\n        let signer = PrivateKeySigner::from_str(private_key.trim()).map_err(|_| {\n            anyhow::anyhow!(\n                \"Signer private key in '{}' is not a valid hex private key\",\n                self.config.signer_private_key_env\n            )\n        })?;\n\n        if signer.address() != self.wallet_address {\n            anyhow::bail!(\n                \"Signer address {} derived from '{}' does not match configured wallet address {}\",\n                signer.address(),\n                self.config.signer_private_key_env,\n                self.wallet_address\n            );\n        }\n\n        self.signer = Some(signer);\n\n        if self.cache.has_database()\n            && let Err(e) = self.reconcile_unresolved_execution().await","sourceCodeStart":2765,"sourceCodeEnd":2801,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/2114cf6f761429e0adb5ca9596fcd7b895b16011/crates/adapters/blockchain/src/execution/client.rs#L2765-L2801","documentation":"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.","triggerScenarios":"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'.","commonSituations":"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.","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."],"exampleFix":"# before (invalid)\nexport SIGNER_KEY=0xdeadbeef   # too short, not 32 bytes\n# .env loader kept the value wrapped in quotes\n\n# after\nexport SIGNER_KEY=0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318","handlingStrategy":"validation","validationCode":"let raw = std::env::var(env_name)?.trim().to_string();\nlet hex = raw.strip_prefix(\"0x\").unwrap_or(&raw);\nif hex.len() != 64 || !hex.chars().all(|c| c.is_ascii_hexdigit()) {\n    anyhow::bail!(\"signer key in '{env_name}' must be 64 hex chars (32 bytes)\");\n}","typeGuard":"fn is_valid_private_key_string(s: &str) -> bool {\n    let h = s.trim().strip_prefix(\"0x\").unwrap_or(s.trim());\n    h.len() == 64 && h.chars().all(|c| c.is_ascii_hexdigit())\n}","tryCatchPattern":"Fail startup with a message naming only the variable (never the value); point the operator at length/charset requirements.","preventionTips":["Validate key format at deployment time, before the node starts.","Store secrets raw (no extra quoting) and beware .env loaders that preserve quotes."],"tags":["secrets","private-key","validation","startup","signer"],"backgroundTag":"invalid-private-key","analyzedSha":"2114cf6f761429e0adb5ca9596fcd7b895b16011","analyzedAt":"2026-08-21T11:28:30.864Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}