{"record":{"id":"12c50a92a2ec5a29","repo":"astrid-runtime/astrid","slug":"invalid-content-name-error","errorCode":null,"errorMessage":"invalid content name {}: {error}","messagePattern":"invalid content name (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/principal_home_migration/publish.rs","lineNumber":85,"sourceCode":"                &source,\n                \"legacy source changed during migration\",\n            ));\n        }\n        match filesystem.stat(&destination) {\n            Ok(existing) => {\n                if existing.kind() != FilesystemEntryKind::File {\n                    return Err(conflict_fs(\n                        &destination,\n                        \"destination kind conflicts with source file\",\n                    ));\n                }\n                verify_file_content(filesystem, &destination, entry)?;\n            },\n            Err(FilesystemError::NotFound(_)) => {\n                astrid_core::platform_fs::verify_no_redirects(&source)?;\n                validate_regular_file(&source)?;\n                let name = ContentName::new(destination.as_str().to_owned()).map_err(|error| {\n                    io::Error::new(\n                        io::ErrorKind::InvalidData,\n                        format!(\"invalid content name {}: {error}\", destination.as_str()),\n                    )\n                })?;\n                new_files.push(ContiguousFileIngest::new(name, source, entry.bytes.get()));\n            },\n            Err(error) => return Err(storage_error(&error)),\n        }\n    }\n    if new_files.is_empty() {\n        return Ok(());\n    }\n    store\n        .put_contiguous_files(StateOwner::Principal(uid), new_files)\n        .map_err(|error| io::Error::other(format!(\"contiguous home import failed: {error}\")))?;\n    for entry in files {\n        let destination = FilesystemPath::new(entry.destination.clone()).map_err(|error| {\n            io::Error::new(","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/principal_home_migration/publish.rs#L67-L103","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet name = ContentName::new(\"Docs/My File.TXT\".to_owned())?; // invalid separators/spaces\n// after\nlet name = ContentName::new(\"docs/my-file.txt\".to_owned())?; // canonical content name","handlingStrategy":"validation","validationCode":"fn validate_content_name(destination: &FilesystemPath) -> io::Result<()> {\n    ContentName::new(destination.as_str().to_owned()).map(|_| ()).map_err(|error| {\n        io::Error::new(io::ErrorKind::InvalidData, format!(\"invalid content name {}: {error}\", destination.as_str()))\n    })\n}","typeGuard":"fn is_valid_content_name(path: &str) -> bool {\n    ContentName::new(path.to_owned()).is_ok()\n}","tryCatchPattern":"match publish_inventory(&store, &fs, uid, &source, entries) {\n    Err(e) if e.kind() == io::ErrorKind::InvalidData && e.to_string().contains(\"invalid content name\") => {\n        eprintln!(\"destination is not a valid content name, regenerate inventory: {e}\");\n    },\n    Err(e) => return Err(e),\n    Ok(()) => {},\n}","preventionTips":["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."],"tags":["rust","migration","content-name","ingest"],"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-17T15:17:12.973Z"}