astrid-runtime/astrid · error · io::Error
legacy state source is redirected or not a directory: {}
Error message
legacy state source is redirected or not a directory: {} What it means
Before retiring the legacy directory-backed state tree, validate_legacy_retirement_candidate checks the configured legacy path with symlink_metadata: if it is a symlink (redirect) or not a real directory, the layout-v2 preflight refuses to proceed with InvalidData. This prevents migrating/retiring data that a symlink silently redirects elsewhere, or a path that never held the legacy state at all.
Source
Thrown at crates/astrid-core/src/dirs_layout_retirement.rs:17
//! No-follow retirement of the released directory-backed state tree.
#[cfg(unix)]
use std::fs::File;
use std::io;
use std::path::Path;
#[cfg(target_os = "linux")]
use std::path::PathBuf;
pub(super) fn validate_legacy_retirement_candidate(path: &Path) -> io::Result<()> {
let metadata = match std::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 state source is redirected or not a directory: {}",
path.display()
),
));
}
validate_legacy_tree(path, legacy_tree_device(&metadata))
}
#[cfg(unix)]
pub(super) fn legacy_tree_device(metadata: &std::fs::Metadata) -> u64 {
use std::os::unix::fs::MetadataExt as _;
metadata.dev()
}
#[cfg(not(unix))]View on GitHub (pinned to affd8760f4)
Solutions
- Remove the symlink and move the real state directory to the configured path (cp -a the target's contents, then delete the link).
- Fix the configuration so the legacy state path points at the actual directory, not a file or a link.
- Verify with: stat <path> — it must show a directory, not 'symbolic link'.
- If there is genuinely no legacy state, ensure the path does not exist at all (the check passes on NotFound).
Example fix
// before ln -s /mnt/data/astrid-state ~/.local/state/astrid // after rm ~/.local/state/astrid mv /mnt/data/astrid-state ~/.local/state/astrid # real directory at configured path
Defensive patterns
Strategy: validation
Validate before calling
use std::path::Path;
fn legacy_path_ok(path: &Path) -> bool {
match std::fs::symlink_metadata(path) {
Ok(m) => !m.file_type().is_symlink() && m.is_dir(),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => true, // no legacy state is fine
Err(_) => false,
}
} Type guard
fn is_plain_directory(p: &Path) -> bool {
std::fs::symlink_metadata(p).map(|m| !m.file_type().is_symlink() && m.is_dir()).unwrap_or(false)
} Try / catch
match result {
Err(e) if e.to_string().contains("redirected or not a directory") => {
eprintln!("fix the configured legacy state path (no symlinks, must be a dir)");
return Err(e);
}
other => other,
} Prevention
- Never let dotfile managers symlink the state directory itself; manage the parent directory instead.
- Before migration, run stat <legacy-path> and confirm it reports a directory, not a symbolic link.
- If no legacy state exists, leave the path absent rather than pointing it at an unrelated file.
- Keep the legacy state path stable across config changes; validate paths after editing configuration.
When it happens
Trigger: Calling preflight_layout_v2_paths / validate_layout_v2_legacy_sources when the legacy state path either is a symlink or resolves to a non-directory (file, socket, etc.). A NotFound path is tolerated (no legacy state), but anything else non-directory fails.
Common situations: Dotfile managers (stow/dotbot) symlinked the state directory; the path was repointed to a file (e.g. a tarball or a moved database file); a config mistake points ASTRID at the wrong path; the state dir was replaced by a mount target that is not a directory.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- layout migration source contains a redirect: {}
- legacy capsule directory is not a regular directory: {}
- legacy capsule entry is not a regular directory: {}
- legacy REPL history is not a regular file: {}
- Astrid home without a layout sentinel is redirected or not a
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/230f11953f701249.
Report an issue: GitHub.