{"record":{"id":"6d6be221813579a0","repo":"astrid-runtime/astrid","slug":"layout-record-has-no-parent","errorCode":null,"errorMessage":"layout record has no parent","messagePattern":"layout record has no parent","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/astrid-core/src/dirs_layout.rs","lineNumber":518,"sourceCode":"fn ensure_migration_capacity(_target: &Path, _source_bytes: u64) -> io::Result<()> {\n    Err(io::Error::new(\n        io::ErrorKind::Unsupported,\n        \"layout migration capacity probing is unavailable in a WebAssembly guest\",\n    ))\n}\n\nfn atomic_write(path: &Path, bytes: &[u8]) -> io::Result<()> {\n    #[cfg(windows)]\n    {\n        crate::platform_fs::atomic_write_private_file(path, bytes)\n    }\n\n    #[cfg(unix)]\n    {\n        use std::os::unix::fs::OpenOptionsExt as _;\n\n        let parent = path.parent().ok_or_else(|| {\n            io::Error::new(io::ErrorKind::InvalidInput, \"layout record has no parent\")\n        })?;\n        std::fs::create_dir_all(parent)?;\n        let name = path\n            .file_name()\n            .and_then(|name| name.to_str())\n            .ok_or_else(|| {\n                io::Error::new(\n                    io::ErrorKind::InvalidInput,\n                    \"layout record has no file name\",\n                )\n            })?;\n        let staged = parent.join(format!(\".{name}.next\"));\n        match std::fs::symlink_metadata(&staged) {\n            Ok(metadata) if metadata.file_type().is_file() => std::fs::remove_file(&staged)?,\n            Ok(_) => {\n                return Err(io::Error::new(\n                    io::ErrorKind::InvalidData,\n                    format!(\"layout staging path is redirected: {}\", staged.display()),","sourceCodeStart":500,"sourceCodeEnd":536,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/dirs_layout.rs#L500-L536","documentation":"atomic_write derives the parent directory of the target path via Path::parent(); if the path has no parent component (e.g. a bare relative file name like \"record.json\"), it raises InvalidInput \"layout record has no parent\" instead of writing into an ambiguous location. The library requires an explicit directory for durable atomic layout-record writes (it must create the parent and fsync it).","triggerScenarios":"Calling write_layout_version with a path such as Path::new(\"version.json\") or any path whose parent() returns None (root-less relative name), so the ok_or_else branch fires in the unix block.","commonSituations":"Passing a bare file name from config instead of a full path; constructing the path by joining onto an empty base; tests or scripts that chdir and pass just a file name.","solutions":["Pass an absolute or otherwise parent-bearing path, e.g. Path::new(\".\").join(\"version.json\") or the layout directory joined with the file name.","Verify the path with path.parent().is_some() before calling the API.","Fix the caller/config that supplies the layout record path so it always includes the directory."],"exampleFix":"// before\nwrite_layout_version(Path::new(\"layout.json\"), &record)?;\n// after\nlet path = layout_dir.join(\"layout.json\");\nwrite_layout_version(&path, &record)?;","handlingStrategy":"validation","validationCode":"fn has_parent(path: &Path) -> bool { path.parent().is_some() }\nif !has_parent(record_path) { return Err(\"record path needs a directory component\"); }","typeGuard":"fn writable_layout_path(path: &Path) -> Option<&Path> {\n    path.parent().map(|_| path)\n}","tryCatchPattern":"if let Err(e) = write_layout_version(path, record) {\n    if e.kind() == io::ErrorKind::InvalidInput && e.to_string().contains(\"no parent\") {\n        eprintln!(\"supply a path with a directory component: {}\", path.display());\n    }\n}","preventionTips":["Always build record paths by joining the layout directory with a file name","Reject bare relative file names in configuration","Unit-test path builders to assert parent() is Some"],"tags":["filesystem","invalid-path","atomic-write"],"backgroundTag":"invalid-argument-value","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}