{"record":{"id":"40514f7225acaa99","repo":"astrid-runtime/astrid","slug":"invaliddata-40514f","errorCode":"InvalidData","errorMessage":"legacy dedicated source is not a regular directory: {}","messagePattern":"legacy dedicated source is not a regular directory: (.+?)","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/legacy_migration_barrier/legacy_tmp.rs","lineNumber":42,"sourceCode":"        for path in [\n            principal.kv_dir(),\n            principal.tokens_dir(),\n            principal.tmp_dir(),\n        ] {\n            tighten_dedicated_tree(&path)?;\n        }\n    }\n    Ok(())\n}\n\nfn tighten_dedicated_tree(path: &Path) -> io::Result<()> {\n    let metadata = match fs::symlink_metadata(path) {\n        Ok(metadata) => metadata,\n        Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(()),\n        Err(error) => return Err(error),\n    };\n    if metadata.file_type().is_symlink() || !metadata.is_dir() {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            format!(\n                \"legacy dedicated source is not a regular directory: {}\",\n                path.display()\n            ),\n        ));\n    }\n    astrid_core::platform_fs::verify_no_redirects(path)?;\n    #[cfg(unix)]\n    {\n        use std::os::unix::fs::MetadataExt as _;\n        if metadata.uid() != nix::unistd::getuid().as_raw() {\n            return Err(io::Error::new(\n                io::ErrorKind::PermissionDenied,\n                format!(\n                    \"legacy dedicated source is not owned by the current user: {}\",\n                    path.display()\n                ),","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/legacy_migration_barrier/legacy_tmp.rs#L24-L60","documentation":"tighten_dedicated_tree tightens permissions on a legacy dedicated directory tree. The path must be a real directory; if symlink_metadata reports a symlink or non-directory, the function aborts with this InvalidData error because tightening a link or file would be meaningless or unsafe. A NotFound path is tolerated and returns Ok.","triggerScenarios":"tighten_dedicated_tree (called by tighten_legacy_dedicated_directories, including recursively) encounters a path whose symlink_metadata shows is_symlink() or !is_dir(); NotFound is silently skipped, anything else non-directory errors.","commonSituations":"A legacy tmp/dedicated directory was replaced by a symlink to /tmp or shared storage; a file was created where the directory is expected; partial cleanup left a broken structure.","solutions":["Replace the symlink/file at the reported path with a real directory","Copy the link target's contents into a genuine directory and remove the link","Remove the stray file if it is leftover debris, then re-run tightening","Fix the tooling that converted the directory into a link"],"exampleFix":"// before: legacy dedicated path is a symlink to /tmp/legacy\n// after\nrm <legacy-dedicated-path>\nmkdir <legacy-dedicated-path>\ncp -a /tmp/legacy/. <legacy-dedicated-path>/","handlingStrategy":"validation","validationCode":"match std::fs::symlink_metadata(path) {\n    Ok(md) if md.file_type().is_symlink() || !md.is_dir() => { /* replace with real dir */ }\n    Ok(_) => {}\n    Err(e) if e.kind() == std::io::ErrorKind::NotFound => {} // tolerated\n    Err(e) => return Err(e),\n}","typeGuard":"fn is_plain_dir(path: &std::path::Path) -> bool {\n    std::fs::symlink_metadata(path).map(|m| !m.file_type().is_symlink() && m.is_dir()).unwrap_or(false)\n}","tryCatchPattern":"if let Err(e) = tighten_legacy_dedicated_directories(&home) {\n    if e.to_string().contains(\"not a regular directory\") {\n        eprintln!(\"replace the path named in the error with a real directory\");\n    }\n}","preventionTips":["Never symlink legacy dedicated directories (e.g. to /tmp or another volume)","Pre-scan the tree with symlink_metadata before tightening","Remove stray files left by partial cleanups"],"tags":["filesystem","symlink","permissions","migration"],"backgroundTag":"path-is-not-a-directory","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"}