{"record":{"id":"9d51eafa9c3e5a7e","repo":"astrid-runtime/astrid","slug":"invalid-runtime-key-replaces-invalid-signing-key","errorCode":null,"errorMessage":"invalid runtime key (replaces 'invalid signing key' in wrapped keypair error: {error})","messagePattern":"invalid runtime key \\(replaces 'invalid signing key' in wrapped keypair error: (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/lib.rs","lineNumber":4461,"sourceCode":"fn audit_mountpoint(_path: &Path) -> std::io::Result<bool> {\n    Ok(false)\n}\n\n/// Load the runtime ed25519 signing key from disk, or generate and persist a new one.\n///\n/// The key file is 32 bytes of raw secret key material at `{keys_dir}/runtime.key`.\n#[cfg(unix)]\nfn load_or_generate_runtime_key(keys_dir: &Path) -> std::io::Result<KeyPair> {\n    astrid_core::platform_fs::ensure_private_directory(keys_dir)?;\n    let key_path = keys_dir.join(\"runtime.key\");\n    if key_path.exists() {\n        astrid_core::platform_fs::validate_private_file(&key_path)?;\n    }\n    let keypair = astrid_crypto::load_or_generate_keypair(&key_path).map_err(|error| {\n        let message = error\n            .to_string()\n            .replacen(\"invalid signing key\", \"invalid runtime key\", 1);\n        std::io::Error::new(error.kind(), message)\n    })?;\n    astrid_core::platform_fs::restrict_private_file(&key_path)?;\n    Ok(keypair)\n}\n\n/// Spawns the persistent-daemon idle monitor.\n///\n/// Ephemeral shutdown is driven by reliable connection lifecycle accounting;\n/// its never-connected fallback is armed by the daemon only after readiness.\n/// Persistent mode remains idle-shutdown-free unless\n/// `ASTRID_IDLE_TIMEOUT_SECS` is set.\n/// Number of permanent internal event bus subscribers that are not client\n/// connections: `KernelRouter` (`kernel.request.*`), `AdminRouter`\n/// (`kernel.admin.*`), the synchronous `ConnectionTracker` (`client.*`),\n/// `EventDispatcher` (all events), the bus activity monitor (all events,\n/// storm diagnostics — see [`bus_monitor::spawn_bus_activity_monitor`]), and\n/// the grant-on-first-use observer (`astrid.v1.approval` — see\n/// [`grant_on_use::spawn_grant_on_use_handler`]).","sourceCodeStart":4443,"sourceCodeEnd":4479,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/lib.rs#L4443-L4479","documentation":"When loading or creating the node's runtime keypair, any error from astrid_crypto::load_or_generate_keypair is preserved but its message is rewritten: the first occurrence of 'invalid signing key' is replaced with 'invalid runtime key'. The io::Error keeps the original error kind and the amended message, so callers see context-appropriate wording for the runtime key file.","triggerScenarios":"Calling the runtime-key setup routine (e.g. daemon startup that loads the keypair from disk) when the key file contains an invalid or corrupt signing key, or the underlying crypto loader fails for permission/format reasons.","commonSituations":"The runtime key file was truncated, hand-generated with the wrong key type, or created by a different/older crypto format; disk corruption; the file was swapped for an unrelated key.","solutions":["Delete the corrupt runtime key file and let the daemon regenerate it (note: this changes node identity)","Restore the key file from backup, keeping correct private-file permissions","Verify the file was produced by the same astrid_crypto version/format","Check file permissions and ownership if the underlying error was access-related"],"exampleFix":"// before: corrupt key file at path\nrm /var/lib/app/runtime.key\n// after: daemon regenerates on next start\nsystemctl restart app-daemon   # load_or_generate_keypair creates a fresh keypair","handlingStrategy":"try-catch","validationCode":"let md = std::fs::metadata(&key_path)?;\nif md.len() == 0 || md.len() > 4096 { eprintln!(\"runtime key file size suspicious\"); }\nlet md2 = std::fs::symlink_metadata(&key_path)?;\nlet mode = md2.permissions().mode();\nif mode & 0o077 != 0 { eprintln!(\"runtime key too permissive\"); }","typeGuard":null,"tryCatchPattern":"match load_runtime_keypair(&path) {\n    Err(e) if e.to_string().contains(\"invalid runtime key\") => {\n        // back up corrupt key, let daemon regenerate\n    }\n    other => other?,\n}","preventionTips":["Never hand-edit or generate key files with external tools","Keep key files on healthy storage with 0600 permissions","Back up the runtime key so it can be restored instead of regenerated"],"tags":["crypto","keypair","config"],"backgroundTag":"invalid-argument-value","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"}