{"record":{"id":"d3ff5c4961c2c33c","repo":"astrid-runtime/astrid","slug":"public-key-must-be-in-ed25519-base64-form-got","errorCode":null,"errorMessage":"public key must be in 'ed25519:<base64>' form, got {wire:?}","messagePattern":"public key must be in 'ed25519:<base64>' form, got (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/distro/sign.rs","lineNumber":79,"sourceCode":"pub(crate) fn lock_signing_digest(lock: &DistroLock) -> anyhow::Result<[u8; 32]> {\n    let bytes = canonical_lock_bytes(lock)?;\n    let mut hasher = blake3::Hasher::new();\n    hasher.update(SIG_DOMAIN_TAG);\n    hasher.update(&bytes);\n    Ok(*hasher.finalize().as_bytes())\n}\n\n/// Sign a lock with `keypair`, returning the hex `Distro.sig` contents.\npub(crate) fn sign_lock(lock: &DistroLock, keypair: &KeyPair) -> anyhow::Result<String> {\n    let digest = lock_signing_digest(lock)?;\n    let sig = keypair.sign(&digest);\n    Ok(sig.to_hex())\n}\n\n/// Parse the `ed25519:<base64>` wire form into a [`PublicKey`].\npub(crate) fn parse_pubkey(wire: &str) -> anyhow::Result<PublicKey> {\n    let b64 = wire.strip_prefix(\"ed25519:\").ok_or_else(|| {\n        anyhow::anyhow!(\"public key must be in 'ed25519:<base64>' form, got {wire:?}\")\n    })?;\n    PublicKey::from_base64(b64).map_err(|e| anyhow::anyhow!(\"invalid ed25519 public key: {e}\"))\n}\n\n/// Render a [`PublicKey`] as `ed25519:<base64>`.\npub(crate) fn pubkey_to_wire(pk: &PublicKey) -> String {\n    format!(\"ed25519:{}\", pk.to_base64())\n}\n\n/// Verify a hex `Distro.sig` against a lock and a public key.\n///\n/// # Errors\n///\n/// Returns an error if the signature is malformed (not 64 hex bytes) or\n/// does not verify against the lock's signing digest under `pubkey`.\npub(crate) fn verify_lock(\n    lock: &DistroLock,\n    sig_hex: &str,","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/distro/sign.rs#L61-L97","documentation":"parse_pubkey expects public keys serialized as the wire string \"ed25519:<base64>\". If the input lacks the \"ed25519:\" prefix, the strip_prefix fails and this error is raised, echoing the received string in debug form. It guards against passing raw base64 keys, other key formats, or entirely wrong strings where a wire-form key is required.","triggerScenarios":"Calling parse_pubkey with a string missing the ed25519: prefix — a bare base64 key, an ed25519 key prefixed differently (e.g. \"Ed25519:\" with wrong case), an empty string, or a value read from a config field that stores a different format. Also exercised by the pubkey_wire_roundtrips test.","commonSituations":"Users pasting a raw base64 public key from another tool into a CLI flag or config; hand-editing a config file and dropping the prefix; mixing up the public key with a signature or secret key.","solutions":["Prefix the key with \"ed25519:\" exactly (lowercase, with the colon) before passing it, e.g. ed25519:<base64>.","If you only have raw base64, construct the wire form programmatically: format!(\"ed25519:{}\", b64).","Regenerate the wire form with pubkey_to_wire from a valid PublicKey instead of hand-assembling the string.","Check the config/flag value wasn't truncated so that only the base64 half remained."],"exampleFix":"// before\nparse_pubkey(\"MCowBQYDK2VwAyEA...\")?;   // missing prefix\n// after\nparse_pubkey(\"ed25519:MCowBQYDK2VwAyEA...\")?;","handlingStrategy":"validation","validationCode":"anyhow::ensure!(wire.starts_with(\"ed25519:\") && wire.len() > \"ed25519:\".len(),\n    \"public key must be 'ed25519:<base64>', got {wire:?}\");","typeGuard":"fn is_pubkey_wire(s: &str) -> bool {\n    s.strip_prefix(\"ed25519:\").map_or(false, |b| !b.is_empty())\n}","tryCatchPattern":"match parse_pubkey(wire) {\n    Ok(pk) => pk,\n    Err(e) if e.to_string().contains(\"must be in 'ed25519:<base64>' form\") => {\n        // auto-heal: caller passed bare base64\n        parse_pubkey(&format!(\"ed25519:{wire}\"))?\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always produce key strings with pubkey_to_wire instead of hand-writing them.","Keep the prefix exactly lowercase \"ed25519:\" with a colon.","Validate config fields containing keys at load time with the prefix check."],"tags":["crypto","ed25519","format-validation","wire-format"],"backgroundTag":"invalid-argument-format","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"}