astrid-runtime/astrid · error

invalid content name

Error message

invalid content name {}: {error}

What it means

When a migration destination does not yet exist in the logical filesystem, the file is ingested into the principal store under a `ContentName` derived from the destination path. If that path is not a valid content name, the library wraps the error into this InvalidData io::Error. It guards the store against ingesting files under names it cannot address or verify later.

Solutions

  1. Check the exact destination string in the error and the ContentName::new constraints; rename the entry's destination to a valid content name.
  2. Regenerate the inventory so file destinations conform to the content-name namespace.
  3. Pre-validate each file destination with ContentName::new before invoking the migration to fail fast.
  4. Confirm the migration receipt/inventory schema version matches the current library version; older generated pages may predate stricter naming rules.

Example fix

// before
let name = ContentName::new("Docs/My File.TXT".to_owned())?; // invalid separators/spaces
// after
let name = ContentName::new("docs/my-file.txt".to_owned())?; // canonical content name
Defensive patterns

Strategy: validation

Validate before calling

fn validate_content_name(destination: &FilesystemPath) -> io::Result<()> {
    ContentName::new(destination.as_str().to_owned()).map(|_| ()).map_err(|error| {
        io::Error::new(io::ErrorKind::InvalidData, format!("invalid content name {}: {error}", destination.as_str()))
    })
}

Type guard

fn is_valid_content_name(path: &str) -> bool {
    ContentName::new(path.to_owned()).is_ok()
}

Try / catch

match publish_inventory(&store, &fs, uid, &source, entries) {
    Err(e) if e.kind() == io::ErrorKind::InvalidData && e.to_string().contains("invalid content name") => {
        eprintln!("destination is not a valid content name, regenerate inventory: {e}");
    },
    Err(e) => return Err(e),
    Ok(()) => {},
}

Prevention

When it happens

Trigger: `publish_directory_files` takes the NotFound branch of `filesystem.stat(&destination)` (new file ingest) and `ContentName::new(destination.as_str())` rejects the destination path — e.g. a destination containing characters or structure outside the content-name namespace, produced from a malformed MigrationEntry.destination that nonetheless passed FilesystemPath::new.

Common situations: Receipt entries generated by a tool using a different naming convention; destinations with reserved names, wrong separators, or empty segments; migrations across library versions where content-name rules were tightened.

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/12c50a92a2ec5a29. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-kernel/src/principal_home_migration/publish.rs:85

                &source,
                "legacy source changed during migration",
            ));
        }
        match filesystem.stat(&destination) {
            Ok(existing) => {
                if existing.kind() != FilesystemEntryKind::File {
                    return Err(conflict_fs(
                        &destination,
                        "destination kind conflicts with source file",
                    ));
                }
                verify_file_content(filesystem, &destination, entry)?;
            },
            Err(FilesystemError::NotFound(_)) => {
                astrid_core::platform_fs::verify_no_redirects(&source)?;
                validate_regular_file(&source)?;
                let name = ContentName::new(destination.as_str().to_owned()).map_err(|error| {
                    io::Error::new(
                        io::ErrorKind::InvalidData,
                        format!("invalid content name {}: {error}", destination.as_str()),
                    )
                })?;
                new_files.push(ContiguousFileIngest::new(name, source, entry.bytes.get()));
            },
            Err(error) => return Err(storage_error(&error)),
        }
    }
    if new_files.is_empty() {
        return Ok(());
    }
    store
        .put_contiguous_files(StateOwner::Principal(uid), new_files)
        .map_err(|error| io::Error::other(format!("contiguous home import failed: {error}")))?;
    for entry in files {
        let destination = FilesystemPath::new(entry.destination.clone()).map_err(|error| {
            io::Error::new(

View on GitHub (pinned to affd8760f4)