astrid-runtime/astrid · error · io::Error

InvalidData

InvalidData

Error message

legacy dedicated source is not a regular directory: {}

What it means

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.

Solutions

  1. Replace the symlink/file at the reported path with a real directory
  2. Copy the link target's contents into a genuine directory and remove the link
  3. Remove the stray file if it is leftover debris, then re-run tightening
  4. Fix the tooling that converted the directory into a link

Example fix

// before: legacy dedicated path is a symlink to /tmp/legacy
// after
rm <legacy-dedicated-path>
mkdir <legacy-dedicated-path>
cp -a /tmp/legacy/. <legacy-dedicated-path>/
Defensive patterns

Strategy: validation

Validate before calling

match std::fs::symlink_metadata(path) {
    Ok(md) if md.file_type().is_symlink() || !md.is_dir() => { /* replace with real dir */ }
    Ok(_) => {}
    Err(e) if e.kind() == std::io::ErrorKind::NotFound => {} // tolerated
    Err(e) => return Err(e),
}

Type guard

fn is_plain_dir(path: &std::path::Path) -> bool {
    std::fs::symlink_metadata(path).map(|m| !m.file_type().is_symlink() && m.is_dir()).unwrap_or(false)
}

Try / catch

if let Err(e) = tighten_legacy_dedicated_directories(&home) {
    if e.to_string().contains("not a regular directory") {
        eprintln!("replace the path named in the error with a real directory");
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/40514f7225acaa99. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-kernel/src/legacy_migration_barrier/legacy_tmp.rs:42

        for path in [
            principal.kv_dir(),
            principal.tokens_dir(),
            principal.tmp_dir(),
        ] {
            tighten_dedicated_tree(&path)?;
        }
    }
    Ok(())
}

fn tighten_dedicated_tree(path: &Path) -> io::Result<()> {
    let metadata = match fs::symlink_metadata(path) {
        Ok(metadata) => metadata,
        Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(()),
        Err(error) => return Err(error),
    };
    if metadata.file_type().is_symlink() || !metadata.is_dir() {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            format!(
                "legacy dedicated source is not a regular directory: {}",
                path.display()
            ),
        ));
    }
    astrid_core::platform_fs::verify_no_redirects(path)?;
    #[cfg(unix)]
    {
        use std::os::unix::fs::MetadataExt as _;
        if metadata.uid() != nix::unistd::getuid().as_raw() {
            return Err(io::Error::new(
                io::ErrorKind::PermissionDenied,
                format!(
                    "legacy dedicated source is not owned by the current user: {}",
                    path.display()
                ),

View on GitHub (pinned to affd8760f4)