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
- Check the exact destination string in the error and the ContentName::new constraints; rename the entry's destination to a valid content name.
- Regenerate the inventory so file destinations conform to the content-name namespace.
- Pre-validate each file destination with ContentName::new before invoking the migration to fail fast.
- 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
- Derive destinations for file entries from existing content names or the library's canonical naming helpers.
- Dry-run the inventory through a validator that checks both FilesystemPath::new and ContentName::new for each file entry.
- Keep the migration inventory generator and the kernel library on matching versions.
- Avoid spaces, backslashes, and uppercase/non-canonical forms in planned destinations.
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
- absent migration source has a digest
- decode migration ledger
- durable capsule disappeared after publish
- durable capsule failed authoritative verification
- historical principal home receipt is missing or changed
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)