{"record":{"id":"1f0c038fd7813918","repo":"astrid-runtime/astrid","slug":"legacy-capsule-entry-has-a-non-utf-8-name","errorCode":null,"errorMessage":"legacy capsule entry has a non-UTF-8 name","messagePattern":"legacy capsule entry has a non-UTF-8 name","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/storage/migration.rs","lineNumber":130,"sourceCode":"        );\n    }\n    astrid_core::platform_fs::verify_no_redirects(&native)\n        .with_context(|| format!(\"verify legacy capsule root {}\", native.display()))?;\n    let mut children = read_dir_sorted(&native)?;\n    let mut report = LegacyCapsuleMigrationReport::default();\n    let registry = store.capsules();\n    let owner = StateOwner::Principal(uid);\n    for (target, target_metadata) in children.drain(..) {\n        if target_metadata.file_type().is_symlink() || !target_metadata.is_dir() {\n            bail!(\n                \"legacy capsule entry is not a regular directory: {}\",\n                target.display()\n            );\n        }\n        let id = target\n            .file_name()\n            .and_then(|name| name.to_str())\n            .ok_or_else(|| anyhow::anyhow!(\"legacy capsule entry has a non-UTF-8 name\"))?;\n        let manifest = astrid_capsule::discovery::load_manifest(&target.join(\"Capsule.toml\"))\n            .with_context(|| format!(\"read legacy capsule manifest {id}\"))?;\n        if manifest.package.name != id {\n            bail!(\n                \"legacy capsule directory {id} does not match manifest id {}\",\n                manifest.package.name\n            );\n        }\n        let meta_bytes = fs::read(target.join(\"meta.json\"))\n            .with_context(|| format!(\"read legacy capsule metadata {id}\"))?;\n        let meta: CapsuleMeta = serde_json::from_slice(&meta_bytes)\n            .with_context(|| format!(\"decode legacy capsule metadata {id}\"))?;\n        if meta.version != manifest.package.version {\n            bail!(\"legacy capsule metadata version differs for {id}\");\n        }\n        // Released pre-authority installs are admitted only through the\n        // existing one-time verifier. It pins their exact manifest,\n        // capabilities, and executable before any durable publication.","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/storage/migration.rs#L112-L148","documentation":"During native-to-legacy capsule migration, `migrate_native_capsules_with_report` uses each installed capsule directory's `file_name()` as the capsule id. If that directory name is not valid UTF-8, `to_str()` fails and this error aborts migration for that entry. The id must be a UTF-8 string because it is later compared against the manifest's `package.name` and used in receipts/receipt paths.","triggerScenarios":"Running `migrate_native_capsules`/`migrate_all_native_capsules_with_report` when the native capsule store contains a directory whose name has non-UTF-8 bytes; the function reads the target directory listing and one `file_name()` fails `to_str()`.","commonSituations":"Capsule directories created by scripts in a non-UTF-8 locale; corrupted or manually copied directory names; upgrading machines where the capsules directory was populated with legacy encodings.","solutions":["Rename the offending capsule directory under the native capsule home to its correct UTF-8 id (must match the `Capsule.toml` `package.name`)","Delete the corrupt directory and reinstall the capsule so the id is derived from a clean manifest","Enumerate candidates first with `find <capsules-home> -maxdepth 1 | grep -Pv '^[\\x20-\\x7E]+$'` to identify non-ASCII names before migrating"],"exampleFix":"// before\ncapsules/\n  caf\\xe9-tools/   # non-UTF-8 dir name\n\n// after\n$ mv capsules/$(printf 'caf\\xe9-tools') capsules/cafe-tools\n$ migrate_native_capsules(home)?;","handlingStrategy":"validation","validationCode":"fn assert_capsule_ids_utf8(capsules_dir: &Path) -> anyhow::Result<()> {\n    for entry in std::fs::read_dir(capsules_dir)? {\n        let entry = entry?;\n        anyhow::ensure!(entry.file_name().to_str().is_some(),\n            \"non-UTF-8 capsule dir: {:?}\", entry.file_name());\n    }\n    Ok(())\n}\nassert_capsule_ids_utf8(&home.join(\"capsules\"))?;","typeGuard":"fn is_utf8_dir_name(entry: &std::fs::DirEntry) -> bool {\n    entry.file_name().to_str().is_some()\n}","tryCatchPattern":"match migrate_native_capsules(home) {\n    Err(e) if e.to_string().contains(\"non-UTF-8 name\") => {\n        // rename the offending directory to its manifest id, then retry\n    }\n    Err(e) => return Err(e),\n    Ok(r) => r,\n}","preventionTips":["Only create capsule directories from manifest ids (UTF-8 by construction)","Pre-flight the capsules directory for non-ASCII names before running migration","Run migration under a UTF-8 locale","Skip-and-report instead of hard-fail when a single legacy entry has an unusable name, if the API surface allows a report-based migration"],"tags":["filesystem","utf-8","migration","identifier","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-14T05:17:10.506Z"}