astrid-runtime/astrid · error
signing key must be exactly 32 raw bytes (got )
Error message
signing key {} must be exactly 32 raw bytes (got {}) What it means
`load_signing_key` reads a file expected to contain a raw 32-byte ed25519 secret key and refuses anything else. The library enforces the exact ed25519 seed length before constructing a `KeyPair`; keys of any other size (e.g. base64 text, PEM, or 64-byte expanded keys) are rejected so signing never proceeds with a malformed key. The key file path is never logged to avoid leaking secrets.
Solutions
- Regenerate or convert the key to exactly 32 raw bytes (e.g. strip a trailing newline, or re-export the seed portion of a 64-byte key).
- If the key is base64/hex encoded, decode it to raw 32 bytes before staging: `base64 -d key.b64 > key.raw`.
- Verify the file: `wc -c keyfile` must print 32, and confirm it is the secret key, not the public key.
Example fix
// before $ head -c 64 expanded.key > signing.key # 64 bytes -> error // after $ head -c 32 expanded.key > signing.key # raw 32-byte ed25519 seed
Defensive patterns
Strategy: validation
Validate before calling
let bytes = std::fs::read(path)?;
if bytes.len() != 32 {
return Err(anyhow!("signing key must be 32 raw bytes, got {}", bytes.len()));
} Type guard
fn is_raw_ed25519_seed(bytes: &[u8]) -> bool { bytes.len() == 32 } Try / catch
match load_signing_key(path) {
Ok(kp) => /* sign */,
Err(e) => eprintln!("check key file is exactly 32 raw bytes: {e:#}"),
} Prevention
- Generate keys with the project's own keygen so they are 32 raw bytes
- Never store PEM/base64 text where a raw key file is expected
- Check file size with `wc -c` before use
- Keep secret-key and public-key files clearly named and separated
When it happens
Trigger: Calling `load_signing_key(path)` (via `run_seal` or the test) when the file at `path` does not exist, is empty, is a text/PEM/base64-encoded key instead of raw bytes, or is a 64-byte (seed+public) key file.
Common situations: Exporting a key from an SSH/OpenSSL tool that writes PEM, copy-pasting a key into a file (adding trailing newline is fine at 33 bytes — still fails), or pointing at the wrong file such as the public key or a 64-byte pkcs8 artifact.
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
- fingerprint Ed25519 public key
- shuttle for ' ' is unsigned (no [distro.signing] or…
- astrid distro apply requires a signed Distro…
- capsule archive already contains
- capsule archive contains duplicate entry
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/c5bfd823ade29337.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-cli/src/commands/distro/seal.rs:198
if candidate.is_file() {
return Ok(candidate);
}
bail!("{} contains no Distro.toml", p.display());
}
if p.is_file() {
return Ok(p.to_path_buf());
}
bail!(
"seal requires a local Distro.toml path or its directory; {distro:?} is not a file or directory"
)
}
/// Load a 32-byte raw ed25519 secret key from `path`. Never logged.
fn load_signing_key(path: &Path) -> anyhow::Result<astrid_crypto::KeyPair> {
let bytes = std::fs::read(path)
.with_context(|| format!("failed to read signing key {}", path.display()))?;
if bytes.len() != 32 {
bail!(
"signing key {} must be exactly 32 raw bytes (got {})",
path.display(),
bytes.len()
);
}
astrid_crypto::KeyPair::from_secret_key(&bytes)
.map_err(|e| anyhow::anyhow!("invalid ed25519 secret key: {e}"))
}
#[cfg(test)]
mod tests {
use super::*;
struct CurrentDirGuard(PathBuf);
impl CurrentDirGuard {
fn set(path: &Path) -> Self {
let original = std::env::current_dir().unwrap();View on GitHub (pinned to affd8760f4)