nautechsystems/nautilus_trader · error
Lighter API secret must be a 40-byte hex private key
Error message
Lighter API secret must be a 40-byte hex private key
What it means
The Lighter private key decoder requires the API secret to decode from hex into exactly 40 bytes (SCALAR_BYTES). The value may optionally have a 0x/0X prefix; after stripping, `hex::decode` must succeed (else a different 'valid hex' error) and the byte length must equal 40. This error means the hex decoded fine but was not 40 bytes.
Source
Thrown at crates/adapters/lighter/src/common/credential.rs:327
.trim()
.parse::<u8>()
.with_context(|| format!("{env_var} must be an API key index in 0..=254"))?;
ensure_api_key_index(index)
}
fn ensure_api_key_index(value: u8) -> anyhow::Result<u8> {
anyhow::ensure!(value <= 254, "Lighter API key index must be in 0..=254");
Ok(value)
}
fn decode_private_key_hex(value: &str) -> anyhow::Result<Vec<u8>> {
let value = value.trim();
let hex = value
.strip_prefix("0x")
.or_else(|| value.strip_prefix("0X"))
.unwrap_or(value);
let bytes = hex::decode(hex).context("Lighter API secret must be valid hex")?;
anyhow::ensure!(
bytes.len() == SCALAR_BYTES,
"Lighter API secret must be a 40-byte hex private key"
);
Ok(bytes)
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
const PRIVATE_KEY_HEX: &str =
"0b8e0f63c24d8baacd9d29ad4e9a4b73c4a8d2bb8b16dc4fa9d7c2e1d3a8b1f0e8d3a4c5b6e7f001";
#[rstest]
fn test_credential_env_vars_mainnet() {
assert_eq!(View on GitHub (pinned to 18893faf8b)
Solutions
- Verify the API secret is the full 40-byte (80 hex character) private key from your Lighter account.
- Re-copy the key carefully, without truncation, optionally with a 0x prefix.
- Check `bytes.len()` from the hex string: 80 hex chars (excluding 0x) is required.
- If you have a different-length key, obtain the correct Lighter API secret rather than padding the key.
Example fix
// before LIGHTER_API_SECRET=abc123 // decodes to 3 bytes // after LIGHTER_API_SECRET=0x<80 hex characters representing 40 bytes>
Defensive patterns
Strategy: validation
Validate before calling
let hex_str = secret.trim().trim_start_matches("0x").trim_start_matches("0X");
assert_eq!(hex_str.len(), 80, "Lighter API secret must be 80 hex chars (40 bytes)"); Type guard
fn is_40_byte_hex(s: &str) -> bool {
let h = s.trim().trim_start_matches("0x").trim_start_matches("0X");
h.len() == 80 && h.chars().all(|c| c.is_ascii_hexdigit())
} Try / catch
match decode_private_key_hex(&secret) {
Ok(key) => use_key(key),
Err(e) => eprintln!("Invalid LIGHTER_API_SECRET: {e:#}; expected 80 hex chars"),
} Prevention
- Check key length (80 hex chars) before deploying config.
- Do not reuse Ethereum 32-byte private keys as Lighter API secrets.
- Beware clipboard truncation when copying secrets.
When it happens
Trigger: Setting the Lighter API secret env var to a hex string that decodes to fewer or more than 40 bytes — e.g. a truncated key, a 32-byte key from another system, or an ed25519 key of unexpected length.
Common situations: Copying an incomplete key (clipboard truncation); using an Ethereum 32-byte private key instead of the Lighter 40-byte API secret; including stray whitespace is handled by trim but extra characters change length.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Lighter API key index must be in 0..=254
- incomplete Lighter credentials: set {api_key_var}, {api_secr
- `api_key`, `api_secret`, `api_passphrase` credentials must b
- Pool identifier must be 42 chars (address) or 66 chars (pool
- Invalid hex characters in: {s}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/49f3c89ff6a9f432.
Report an issue: GitHub.