{"record":{"id":"e32d1a9a4c3a583d","repo":"astrid-runtime/astrid","slug":"principal-alias-has-an-invalid-genesis-public-ke","errorCode":null,"errorMessage":"principal {alias} has an invalid genesis public key: {error}","messagePattern":"principal (.+?) has an invalid genesis public key: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/principal_home_migration/unbound.rs","lineNumber":222,"sourceCode":"    Ok(true)\n}\n\nfn genesis_public_key_bytes(home: &AstridHome, alias: &PrincipalId) -> io::Result<[u8; 32]> {\n    let profile =\n        PrincipalProfile::load_required(home, alias).map_err(|error| profile_io(&error))?;\n    let device = profile\n        .auth\n        .public_keys\n        .iter()\n        .min_by_key(|device| (device.created_at, device.key_id.as_str()))\n        .ok_or_else(|| {\n            io::Error::new(\n                io::ErrorKind::InvalidData,\n                format!(\"principal {alias} has no Ed25519 key for genesis identity\"),\n            )\n        })?;\n    let public_key = astrid_crypto::PublicKey::from_hex(&device.pubkey).map_err(|error| {\n        io::Error::new(\n            io::ErrorKind::InvalidData,\n            format!(\"principal {alias} has an invalid genesis public key: {error}\"),\n        )\n    })?;\n    Ok(public_key.into())\n}\n\nfn quarantine_entry(\n    home: &AstridHome,\n    source: &Path,\n    file_name: &OsStr,\n    reason: &str,\n) -> io::Result<()> {\n    let quarantine_root = home.migrations_dir().join(QUARANTINE_DIR);\n    astrid_core::platform_fs::ensure_private_directory(&quarantine_root)?;\n    let destination = unique_quarantine_path(&quarantine_root, file_name)?;\n    let source_parent = source.parent().map(Path::to_path_buf);\n    fs::rename(source, &destination).map_err(|error| {","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/principal_home_migration/unbound.rs#L204-L240","documentation":"Thrown by genesis_public_key_bytes when the selected device key's hex string cannot be decoded into an astrid_crypto::PublicKey via from_hex. The profile selected a key (so one exists) but its pubkey bytes are not a valid Ed25519 public key in hex — wrong length or non-hex characters. The underlying decode error is embedded in the message.","triggerScenarios":"genesis_public_key_bytes (via mint_valid_leftover) calls PublicKey::from_hex(&device.pubkey) on the earliest device key and hex decoding or key-length validation fails.","commonSituations":"A profile with a truncated or padded pubkey string from a buggy legacy writer; a placeholder like \"<pubkey>\" or a \"0x...\" prefix in hand-edited JSON; a key of a different algorithm stored in the pubkey field; whitespace/case issues if from_hex is strict.","solutions":["Fix the device.pubkey field so it contains a valid Ed25519 public key as plain hex of the expected length.","Re-export the profile from the legacy application so it writes a correct key.","Remove/quarantine the principal if the key cannot be recovered, instead of minting it.","Validate profile keys with PublicKey::from_hex before starting migration to catch bad entries early."],"exampleFix":"// before\n\"pubkey\": \"0xAB12CD...\"          // 0x prefix, invalid\n// after\n\"pubkey\": \"ab12cd34...\"          // plain lowercase hex, 64 chars for Ed25519","handlingStrategy":"validation","validationCode":"fn pubkey_is_valid_hex(s: &str) -> bool {\n    astrid_crypto::PublicKey::from_hex(s).is_ok()\n}","typeGuard":null,"tryCatchPattern":"match mint_valid_leftover(entry) {\n    Err(e) if e.to_string().contains(\"invalid genesis public key\") => {\n        // re-export or quarantine the principal with the bad key\n        quarantine(entry)?;\n    }\n    other => other?,\n}","preventionTips":["Pre-validate all device pubkey hex strings with from_hex before migration.","Store keys as plain lowercase hex without 0x prefixes or whitespace.","Re-export profiles from the legacy writer instead of manual edits.","Confirm all stored keys are Ed25519 of the expected byte length."],"tags":["crypto","hex","migration","identity","rust"],"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"}