nikivdev/code · error
invalid secret key length
Error message
invalid secret key length
What it means
decode_secret requires the base58-decoded bytes to be exactly 32 bytes (x25519 scalar). If decoding succeeds but the length is wrong, this error is thrown. The string looks like a valid secret but encodes the wrong amount of key material.
Source
Thrown at src/sealer_crypto.rs:89
let nonce = derive_nonce(nonce_material);
let cipher = XSalsa20Poly1305::new(&shared_secret.into());
let plaintext = cipher
.decrypt(&nonce.into(), sealed_message)
.map_err(|_| anyhow::anyhow!("failed to unseal message"))?;
Ok(plaintext)
}
fn decode_secret(value: &str) -> Result<[u8; 32]> {
let encoded = value
.strip_prefix(SECRET_PREFIX)
.ok_or_else(|| anyhow::anyhow!("invalid sealer secret prefix"))?;
let bytes = bs58::decode(encoded)
.into_vec()
.map_err(|e| anyhow::anyhow!("invalid base58 secret: {e}"))?;
bytes
.as_slice()
.try_into()
.map_err(|_| anyhow::anyhow!("invalid secret key length"))
}
fn decode_id(value: &str) -> Result<[u8; 32]> {
let encoded = value
.strip_prefix(ID_PREFIX)
.ok_or_else(|| anyhow::anyhow!("invalid sealer id prefix"))?;
let bytes = bs58::decode(encoded)
.into_vec()
.map_err(|e| anyhow::anyhow!("invalid base58 id: {e}"))?;
bytes
.as_slice()
.try_into()
.map_err(|_| anyhow::anyhow!("invalid public key length"))
}
fn derive_nonce(nonce_material: &[u8]) -> [u8; 24] {
let hash = blake3::hash(nonce_material);
let mut nonce = [0u8; 24];View on GitHub (pinned to a747e741ae)
Solutions
- Provide the complete 32-byte secret; re-copy the full value.
- Regenerate via create_sealer_identity / new_x25519_private_key and re-seal any values.
- Re-encode exactly 32 bytes as "sealerSecret_z" + base58 if migrating.
- Pre-validate: decode and assert 32-byte length before calling seal/unseal.
Example fix
// before: decodes to 24 bytes
let k = decode_secret("sealerSecret_zTooShort")?;
// after: full 32-byte key
let k = decode_secret("sealerSecret_zFull32ByteBase58Body...")?; Defensive patterns
Strategy: validation
Validate before calling
fn decode_secret_len_ok(s: &str) -> bool {
s.strip_prefix("sealerSecret_z")
.and_then(|b| bs58::decode(b).into_vec().ok())
.map(|v| v.len() == 32)
.unwrap_or(false)
} Try / catch
match unseal(blob, recipient_secret, sender_id, nonce) {
Err(e) if e.to_string().contains("invalid secret key length") => {
eprintln!("recipient secret is not a 32-byte x25519 key; regenerate identity");
return Err(e);
}
other => other?,
} Prevention
- Generate secrets exclusively with new_x25519_private_key (32 bytes).
- Check decoded length once at config load and fail fast.
- Never concatenate or pad key strings by hand.
- When importing keys, verify byte length before re-encoding with the prefix.
When it happens
Trigger: Calling seal or unseal with a prefixed secret whose decoded length is not 32 bytes — truncated keys, keys from other schemes, or accidental concatenation.
Common situations: Truncated paste into config, secrets generated by incompatible tooling, or editing the secret by hand.
Related errors
- invalid sealer secret length
- invalid sealer secret prefix
- invalid base58 sealer secret: {e}
- failed to seal message
- failed to unseal message
AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01).
Data as JSON: /api/errors/13adea282a41d01d.
Report an issue: GitHub.