astrid-runtime/astrid · error

private path is not a directory

Error message

private path is not a directory

What it means

On targets that are neither Unix nor Windows, validate_private_directory falls back to a weak check: it only verifies the path is a directory via symlink_metadata. This error means the given path exists but is not a directory (e.g. it is a file or symlink to a file), so the private-directory contract cannot be validated.

Solutions

  1. Check the path and replace the file with the intended directory, or point configuration at the correct directory path.
  2. Create the directory first (ensure_private_directory / create_dir_all) before validating.
  3. If you only need existence+type checks on exotic targets, guard the call with std::path::Path::is_dir() first.

Example fix

// before
validate_private_directory(&cfg.private_dir)?;
// after
if !cfg.private_dir.is_dir() {
    return Err(format!("{} is not a directory; check your config", cfg.private_dir.display()).into());
}
validate_private_directory(&cfg.private_dir)?;
Defensive patterns

Strategy: validation

Validate before calling

if !path.is_dir() {
    return Err(format!("private path {} is not a directory", path.display()));
}

Type guard

fn is_real_directory(p: &std::path::Path) -> bool {
    std::fs::symlink_metadata(p).map(|m| m.is_dir()).unwrap_or(false)
}

Try / catch

match validate_private_directory(&path) {
    Err(e) if e.to_string().contains("not a directory") => {
        std::fs::create_dir_all(&path)?;
        validate_private_directory(&path)?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling validate_private_directory(path) on a non-unix/non-windows target where `path` resolves to a regular file, device, or other non-directory entry.

Common situations: Config pointing at a file instead of a directory; a stale file left where a data directory should be; porting the library to a platform (e.g. wasm) with the wrong path configured.

Related errors


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

Appendix: source

Thrown at crates/astrid-core/src/platform_fs.rs:199

///
/// Returns an error when the directory is missing, redirected, not owned by the
/// current user, or does not satisfy the platform private-access policy.
pub fn validate_private_directory(path: &Path) -> io::Result<()> {
    #[cfg(unix)]
    {
        validate_private_directory_unix(path)
    }

    #[cfg(windows)]
    {
        windows::ensure_private_directory(path)
    }

    #[cfg(not(any(unix, windows)))]
    {
        let metadata = std::fs::symlink_metadata(path)?;
        if !metadata.is_dir() {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "private path is not a directory",
            ));
        }
        Ok(())
    }
}

/// Rename one filesystem entry with the strongest supported namespace
/// durability for the host platform.
///
/// Windows uses `MoveFileExW(MOVEFILE_WRITE_THROUGH)`, which does not return
/// until the move has been flushed. Unix callers must still synchronize the
/// affected parent directories after this atomic rename.
///
/// Windows rejects an existing destination because the write-through move does
/// not request replacement. Other platforms retain `std::fs::rename`
/// replacement semantics. Security-sensitive callers remain responsible for

View on GitHub (pinned to affd8760f4)