{"record":{"id":"4a612d98f3d51aa2","repo":"astrid-runtime/astrid","slug":"invalid-ed25519-secret-key-e","errorCode":null,"errorMessage":"invalid ed25519 secret key: {e}","messagePattern":"invalid ed25519 secret key: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/distro/seal.rs","lineNumber":205,"sourceCode":"    }\n    bail!(\n        \"seal requires a local Distro.toml path or its directory; {distro:?} is not a file or directory\"\n    )\n}\n\n/// Load a 32-byte raw ed25519 secret key from `path`. Never logged.\nfn load_signing_key(path: &Path) -> anyhow::Result<astrid_crypto::KeyPair> {\n    let bytes = std::fs::read(path)\n        .with_context(|| format!(\"failed to read signing key {}\", path.display()))?;\n    if bytes.len() != 32 {\n        bail!(\n            \"signing key {} must be exactly 32 raw bytes (got {})\",\n            path.display(),\n            bytes.len()\n        );\n    }\n    astrid_crypto::KeyPair::from_secret_key(&bytes)\n        .map_err(|e| anyhow::anyhow!(\"invalid ed25519 secret key: {e}\"))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    struct CurrentDirGuard(PathBuf);\n\n    impl CurrentDirGuard {\n        fn set(path: &Path) -> Self {\n            let original = std::env::current_dir().unwrap();\n            std::env::set_current_dir(path).unwrap();\n            Self(original)\n        }\n    }\n\n    fn run_bare_cwd_child(child_name: &str, marker: &str) {\n        let result_dir = tempfile::tempdir().unwrap();","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/distro/seal.rs#L187-L223","documentation":"load_signing_key reads a signing key file, requires exactly 32 raw bytes, and then hands them to astrid_crypto::KeyPair::from_secret_key. If the cryptographic layer still rejects the bytes (not a valid ed25519 scalar), the underlying crypto error is wrapped into \"invalid ed25519 secret key: {e}\". The file exists and is the right length; its content just isn't a usable ed25519 secret key.","triggerScenarios":"Running `seal` (run_seal) with a key path whose 32 bytes are rejected by ed25519 parsing — e.g. a base64/hex-encoded key stored raw-decoded incorrectly, an all-zero or out-of-range scalar, or a truncated/corrupted keyfile that coincidentally is 32 bytes. Also hit intentionally by the test load_signing_key_rejects_wrong_length.","commonSituations":"Generating the key with a different tool that stores it hex/base64 encoded while seal expects raw bytes; copying the wrong file (e.g. a public-key file or unrelated 32-byte blob) as the signing key; file corruption after a failed transfer.","solutions":["Regenerate the signing key with the tooling that emits 32 raw ed25519 secret-key bytes and point the seal command at the new file.","If your key is stored hex- or base64-encoded, decode it to 32 raw bytes before writing it to the keyfile.","Verify file contents: `wc -c` should report exactly 32 bytes and the bytes should be a valid ed25519 scalar (not the public key).","Restore the keyfile from a known-good backup if it was corrupted in transit."],"exampleFix":"// before: base64 text file fed to seal\n SigningKeyPath=/home/me/distro.key   // contains 'dGhpcyBpcyBiYXNlNjQuLi4='\n// after\n$ base64 -d distro.key.b64 > distro.key && wc -c distro.key  # must be 32\nSigningKeyPath=/home/me/distro.key","handlingStrategy":"validation","validationCode":"let bytes = std::fs::read(path)?;\nanyhow::ensure!(bytes.len() == 32, \"signing key {} must be 32 raw bytes, got {}\", path.display(), bytes.len());\nanyhow::ensure!(bytes.iter().any(|&b| b != 0), \"signing key must not be all zeros\");","typeGuard":null,"tryCatchPattern":"match load_signing_key(&path) {\n    Ok(kp) => kp,\n    Err(e) if e.to_string().starts_with(\"invalid ed25519 secret key\") => {\n        eprintln!(\"keyfile content is not a raw ed25519 secret; regenerate or decode it first\");\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Store signing keys as exactly 32 raw bytes — never hex/base64 text in the keyfile.","Regenerate keys with the bundled tooling rather than external generators.","Back up keyfiles and verify byte length after any transfer."],"tags":["crypto","ed25519","signing-key","invalid-key"],"backgroundTag":"invalid-key-material","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}