astrid-runtime/astrid · error

legacy capsule entry has a non-UTF-8 name

Error message

legacy capsule entry has a non-UTF-8 name

What it means

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.

Source

Thrown at crates/astrid-capsule-install/src/storage/migration.rs:130

        );
    }
    astrid_core::platform_fs::verify_no_redirects(&native)
        .with_context(|| format!("verify legacy capsule root {}", native.display()))?;
    let mut children = read_dir_sorted(&native)?;
    let mut report = LegacyCapsuleMigrationReport::default();
    let registry = store.capsules();
    let owner = StateOwner::Principal(uid);
    for (target, target_metadata) in children.drain(..) {
        if target_metadata.file_type().is_symlink() || !target_metadata.is_dir() {
            bail!(
                "legacy capsule entry is not a regular directory: {}",
                target.display()
            );
        }
        let id = target
            .file_name()
            .and_then(|name| name.to_str())
            .ok_or_else(|| anyhow::anyhow!("legacy capsule entry has a non-UTF-8 name"))?;
        let manifest = astrid_capsule::discovery::load_manifest(&target.join("Capsule.toml"))
            .with_context(|| format!("read legacy capsule manifest {id}"))?;
        if manifest.package.name != id {
            bail!(
                "legacy capsule directory {id} does not match manifest id {}",
                manifest.package.name
            );
        }
        let meta_bytes = fs::read(target.join("meta.json"))
            .with_context(|| format!("read legacy capsule metadata {id}"))?;
        let meta: CapsuleMeta = serde_json::from_slice(&meta_bytes)
            .with_context(|| format!("decode legacy capsule metadata {id}"))?;
        if meta.version != manifest.package.version {
            bail!("legacy capsule metadata version differs for {id}");
        }
        // Released pre-authority installs are admitted only through the
        // existing one-time verifier. It pins their exact manifest,
        // capabilities, and executable before any durable publication.

View on GitHub (pinned to affd8760f4)

Solutions

  1. Rename the offending capsule directory under the native capsule home to its correct UTF-8 id (must match the `Capsule.toml` `package.name`)
  2. Delete the corrupt directory and reinstall the capsule so the id is derived from a clean manifest
  3. Enumerate candidates first with `find <capsules-home> -maxdepth 1 | grep -Pv '^[\x20-\x7E]+$'` to identify non-ASCII names before migrating

Example fix

// before
capsules/
  caf\xe9-tools/   # non-UTF-8 dir name

// after
$ mv capsules/$(printf 'caf\xe9-tools') capsules/cafe-tools
$ migrate_native_capsules(home)?;
Defensive patterns

Strategy: validation

Validate before calling

fn assert_capsule_ids_utf8(capsules_dir: &Path) -> anyhow::Result<()> {
    for entry in std::fs::read_dir(capsules_dir)? {
        let entry = entry?;
        anyhow::ensure!(entry.file_name().to_str().is_some(),
            "non-UTF-8 capsule dir: {:?}", entry.file_name());
    }
    Ok(())
}
assert_capsule_ids_utf8(&home.join("capsules"))?;

Type guard

fn is_utf8_dir_name(entry: &std::fs::DirEntry) -> bool {
    entry.file_name().to_str().is_some()
}

Try / catch

match migrate_native_capsules(home) {
    Err(e) if e.to_string().contains("non-UTF-8 name") => {
        // rename the offending directory to its manifest id, then retry
    }
    Err(e) => return Err(e),
    Ok(r) => r,
}

Prevention

When it happens

Trigger: 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()`.

Common situations: 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.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/1f0c038fd7813918. Report an issue: GitHub.