astrid-runtime/astrid · error
invalid runtime key (replaces 'invalid signing key' in…
Error message
invalid runtime key (replaces 'invalid signing key' in wrapped keypair error: {error}) What it means
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.
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
Example fix
// before: corrupt key file at path rm /var/lib/app/runtime.key // after: daemon regenerates on next start systemctl restart app-daemon # load_or_generate_keypair creates a fresh keypair
Defensive patterns
Strategy: try-catch
Validate before calling
let md = std::fs::metadata(&key_path)?;
if md.len() == 0 || md.len() > 4096 { eprintln!("runtime key file size suspicious"); }
let md2 = std::fs::symlink_metadata(&key_path)?;
let mode = md2.permissions().mode();
if mode & 0o077 != 0 { eprintln!("runtime key too permissive"); } Try / catch
match load_runtime_keypair(&path) {
Err(e) if e.to_string().contains("invalid runtime key") => {
// back up corrupt key, let daemon regenerate
}
other => other?,
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- ASTRID_ENFORCED_DISTRO must not be empty
- ASTRID_HOME must be an absolute path
- branding.accent-color
- branding.primary-color
- build_host_state
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/9d51eafa9c3e5a7e.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-kernel/src/lib.rs:4461
fn audit_mountpoint(_path: &Path) -> std::io::Result<bool> {
Ok(false)
}
/// Load the runtime ed25519 signing key from disk, or generate and persist a new one.
///
/// The key file is 32 bytes of raw secret key material at `{keys_dir}/runtime.key`.
#[cfg(unix)]
fn load_or_generate_runtime_key(keys_dir: &Path) -> std::io::Result<KeyPair> {
astrid_core::platform_fs::ensure_private_directory(keys_dir)?;
let key_path = keys_dir.join("runtime.key");
if key_path.exists() {
astrid_core::platform_fs::validate_private_file(&key_path)?;
}
let keypair = astrid_crypto::load_or_generate_keypair(&key_path).map_err(|error| {
let message = error
.to_string()
.replacen("invalid signing key", "invalid runtime key", 1);
std::io::Error::new(error.kind(), message)
})?;
astrid_core::platform_fs::restrict_private_file(&key_path)?;
Ok(keypair)
}
/// Spawns the persistent-daemon idle monitor.
///
/// Ephemeral shutdown is driven by reliable connection lifecycle accounting;
/// its never-connected fallback is armed by the daemon only after readiness.
/// Persistent mode remains idle-shutdown-free unless
/// `ASTRID_IDLE_TIMEOUT_SECS` is set.
/// Number of permanent internal event bus subscribers that are not client
/// connections: `KernelRouter` (`kernel.request.*`), `AdminRouter`
/// (`kernel.admin.*`), the synchronous `ConnectionTracker` (`client.*`),
/// `EventDispatcher` (all events), the bus activity monitor (all events,
/// storm diagnostics — see [`bus_monitor::spawn_bus_activity_monitor`]), and
/// the grant-on-first-use observer (`astrid.v1.approval` — see
/// [`grant_on_use::spawn_grant_on_use_handler`]).View on GitHub (pinned to affd8760f4)