{"record":{"id":"6a9eae675073118d","repo":"astrid-runtime/astrid","slug":"unknown-migration-component-name-name","errorCode":null,"errorMessage":"unknown migration component name: {name}","messagePattern":"unknown migration component name: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/legacy_migration_barrier/ledger.rs","lineNumber":546,"sourceCode":"    }\n    Ok(())\n}\n\nfn validate_component_name(name: &str) -> io::Result<()> {\n    match name {\n        \"system:state-db\"\n        | \"system:cow\"\n        | \"system:invites\"\n        | \"system:pair-tokens\"\n        | \"system:gateway-revocations\"\n        | \"system:host-secrets\"\n        | \"system:capsule-authority\"\n        | \"system:fresh-layout\" => return Ok(()),\n        _ => {},\n    }\n    let parts = name.split(':').collect::<Vec<_>>();\n    if parts.len() < 3 || parts[0] != \"principal\" {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            format!(\"unknown migration component name: {name}\"),\n        ));\n    }\n    PrincipalUid::from_str(parts[1]).map_err(|_| {\n        io::Error::new(\n            io::ErrorKind::InvalidData,\n            format!(\"migration component has a non-canonical principal UID: {name}\"),\n        )\n    })?;\n    let valid_shape = match parts[2] {\n        \"home\" | \"profile\" | \"capsules\" | \"secrets\" | \"audit\" | \"logs\" | \"tmp\" | \"distro-lock\"\n        | \"distro-init\" => parts.len() == 3,\n        \"env\" | \"secret\" => parts.len() == 4 && !parts[3].is_empty(),\n        _ => false,\n    };\n    if !valid_shape {\n        return Err(io::Error::new(","sourceCodeStart":528,"sourceCodeEnd":564,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/legacy_migration_barrier/ledger.rs#L528-L564","documentation":"`validate_component_name` enforces the canonical naming scheme for migration ledger components. A name must either be one of the known `system:*` components or a `principal:<uid>:<kind>` name with at least three colon-separated parts starting with `principal`. This error is thrown when the name matches neither form, so the ledger contains a component the library does not recognize.","triggerScenarios":"Calling `validate_ledger_shape` (via `write_ledger` or any ledger decode path) with a `MigrationLedger` whose `components` array contains a name like `\"home\"`, `\"state\"`, `\"misc:foo\"`, or a `principal:...` name split into fewer than 3 parts (e.g. `\"principal:01HABC\"`).","commonSituations":"Hand-editing the ledger JSON and mistyping a component name; a script generating ledger entries with the wrong prefix; a ledger written by an incompatible/newer tool version using unknown component names.","solutions":["Correct the component name in the ledger to the canonical form `principal:<uid>:<kind>` (kind one of home|profile|capsules|secrets|audit|logs|tmp|distro-lock|distro-init, or env/secret with an extra non-empty segment).","If the component is a system component, use the exact registered name (e.g. `system:state-db`, `system:cow`, `system:invites`, `system:pair-tokens`, `system:gateway-revocations`, `system:host-secrets`, `system:capsule-authority`, `system:fresh-layout`).","Rebuild the ledger through the library's write path instead of editing JSON by hand.","Ensure the tool that produced the ledger is the same version as the library validating it."],"exampleFix":"// before\n{\"name\": \"home\", ...}\n// after\n{\"name\": \"principal:01H8X7Y3Z9Q:home\", ...}","handlingStrategy":"validation","validationCode":"// Validate component names before handing a ledger to the library\nfn is_valid_component_name(name: &str) -> bool {\n    const SYSTEM: [&str; 8] = [\"system:state-db\",\"system:cow\",\"system:invites\",\"system:pair-tokens\",\n        \"system:gateway-revocations\",\"system:host-secrets\",\"system:capsule-authority\",\"system:fresh-layout\"];\n    if SYSTEM.contains(&name) { return true; }\n    let parts: Vec<&str> = name.split(':').collect();\n    parts.len() >= 3 && parts[0] == \"principal\"\n}","typeGuard":"fn is_principal_component(name: &str) -> Option<(&str, &str)> {\n    let parts: Vec<&str> = name.split(':').collect();\n    if parts.len() >= 3 && parts[0] == \"principal\" { Some((parts[1], parts[2])) } else { None }\n}","tryCatchPattern":null,"preventionTips":["Always build component names with the library's helpers, never string concatenation in scripts","Use `principal:<canonical-uid>:<kind>` with a kind from the documented set","Never hand-edit ledger JSON; use write_ledger","Pin the tool version used to write ledgers to the library version validating them"],"tags":["migration","validation","naming","rust"],"backgroundTag":"invalid-identifier-format","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}