BloopAI/vibe-kanban · error · std::io::Error
server signing key file has invalid length (expected 32 byte
Error message
server signing key file has invalid length (expected 32 bytes)
What it means
load_or_generate loads the relay server's Ed25519 signing key from a file that must contain exactly 32 bytes of raw key material. If the file exists but its length differs (corruption, truncation, base64/PEM-encoded text, wrong file), the bytes cannot fit [u8; 32] and this error is returned.
Source
Thrown at crates/relay-control/src/signing.rs:145
#[derive(Clone)]
pub struct RelaySigningService {
sessions: Arc<RwLock<HashMap<Uuid, RelaySigningSession>>>,
server_signing_key: Arc<SigningKey>,
}
impl RelaySigningService {
pub fn new(server_signing_key: SigningKey) -> Self {
Self {
sessions: Arc::new(RwLock::new(HashMap::new())),
server_signing_key: Arc::new(server_signing_key),
}
}
pub fn load_or_generate(key_path: &Path) -> io::Result<Self> {
let key = if let Ok(bytes) = fs::read(key_path) {
let arr: [u8; 32] = bytes.try_into().map_err(|_| {
io::Error::new(
io::ErrorKind::InvalidData,
"server signing key file has invalid length (expected 32 bytes)",
)
})?;
SigningKey::from_bytes(&arr)
} else {
let key = SigningKey::generate(&mut OsRng);
if let Some(parent) = key_path.parent() {
fs::create_dir_all(parent)?;
}
let tmp = key_path.with_extension("tmp");
fs::write(&tmp, key.to_bytes())?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;View on GitHub (pinned to 4deb7eca8f)
Solutions
- Delete the invalid key file and let load_or_generate regenerate a fresh one (re-register any clients that pinned the old key).
- If the key must be preserved, decode it and write exactly 32 raw bytes to the file (no hex, base64, or newlines).
- Verify the file: wc -c < key_path must print 32.
- Ensure secret mounts/copy scripts don't inject encoding or trailing newlines into the key file.
Example fix
// before (writes base64 text) openssl genpkey ... | base64 > key_path // after (writes raw 32 bytes) openssl genpkey -algorithm ed25519 | openssl pkey -outform DER -out /tmp/k.der tail -c 32 /tmp/k.der > key_path
Defensive patterns
Strategy: validation
Validate before calling
fn key_file_valid(path: &Path) -> bool {
std::fs::metadata(path).map(|m| m.len() == 32).unwrap_or(false)
}
if !key_file_valid(key_path) {
std::fs::remove_file(key_path).ok(); // let load_or_generate regenerate
} Type guard
fn is_raw_32_byte_key(bytes: &[u8]) -> bool {
bytes.len() == 32
} Try / catch
match SigningKey::load_or_generate(key_path) {
Err(e) if e.kind() == ErrorKind::InvalidData
&& e.to_string().contains("invalid length") => {
std::fs::remove_file(key_path)?;
SigningKey::load_or_generate(key_path)? // regenerated fresh
}
other => other,
} Prevention
- Never write encoded (hex/base64/PEM) key material to the key path.
- Verify key files are exactly 32 bytes after provisioning scripts run.
- Backup the key file atomically so it can never be truncated mid-write.
When it happens
Trigger: Relay control startup with a key_path whose file content is not exactly 32 raw bytes — e.g. a key saved as hex/base64 text, a truncated file, or a different key file placed at the expected path.
Common situations: Manually generating a key and writing it encoded (openssl output) instead of raw; a partially failed write leaving a truncated file; mounting a config secret that is PEM/ASCII-armored; copying the wrong file to the key path.
Related errors
- This host is not paired with your browser. Pair it in Relay
- No setup script configured for this project
- No cleanup script configured for this project
- No archive script configured for this project
- Server proof verification failed.
AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29).
Data as JSON: /api/errors/6136fd5cef1be76c.
Report an issue: GitHub.