jdx/mise · error
{} is not a directory; resolve its type before pulling
Error message
{} is not a directory; resolve its type before pulling What it means
observe() snapshots a directory's identity (dev, ino, mode) for permission planning. If the path exists but is not a directory (file or symlink), planning cannot proceed safely; the caller must resolve the path's type before a pull.
Source
Thrown at src/system/history/sync/directories.rs:23
use crate::system::history::{
journal, manifest::Manifest, shadow::HistoryRepo, tracked::TrackedSet,
};
#[derive(Clone, Debug)]
pub(super) struct Step {
pub path: PathBuf,
before: Option<(u64, u64, u32)>,
desired: u32,
written: Option<(u64, u64, u32)>,
}
#[cfg(unix)]
fn observe(path: &std::path::Path) -> Result<Option<(u64, u64, u32)>> {
use std::os::unix::fs::MetadataExt;
match std::fs::symlink_metadata(path) {
Ok(meta) if meta.is_dir() => Ok(Some((meta.dev(), meta.ino(), meta.mode() & 0o777))),
Ok(_) => bail!(
"{} is not a directory; resolve its type before pulling",
crate::file::display_path(path)
),
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(None),
Err(err) => Err(err.into()),
}
}
#[cfg(not(unix))]
fn observe(_path: &std::path::Path) -> Result<Option<(u64, u64, u32)>> {
Ok(None)
}
pub(super) fn plan(repo: &HistoryRepo, tracked: &TrackedSet, tree: &str) -> Result<Vec<Step>> {
if !cfg!(unix) {
return Ok(vec![]);
}
let local = repo.ref_oid(HistoryRepo::HISTORY_REF)?;View on GitHub (pinned to afd2eddd3a)
Solutions
- Check the path (`ls -la <path>`); if it should be a directory, remove the file/symlink and recreate the directory, then retry the pull.
- If the path should no longer be a directory, update the setup-history configuration to stop tracking it as one.
- Resolve the path type in your setup before running pull (e.g. ensure the real directory exists).
Example fix
// before ~/.config/app (regular file) // after rm ~/.config/app && mkdir ~/.config/app
Defensive patterns
Strategy: validation
Validate before calling
let meta = std::fs::symlink_metadata(path)?;
if !meta.is_dir() {
// recreate as a directory before pulling
} Type guard
fn is_directory(p: &Path) -> bool {
std::fs::symlink_metadata(p).map(|m| m.is_dir()).unwrap_or(false)
} Prevention
- Don't replace tracked directories with files or symlinks
- Recreate directories with mkdir after accidental deletion
- Verify path types before restores or imports
When it happens
Trigger: A path expected to be a directory in setup history was replaced by a file or symlink; plan/validate/apply/verify_written encounter a non-directory at a tracked directory path.
Common situations: A sync or restore replaced the directory with a file; a user deleted the directory and created a file of the same name; a symlink pointing at a directory is treated per its own type.
Related errors
- cannot create task stub directory because {} is not a direct
- cannot replace task stub directory because {} is empty
- {} changed during recovery; left untouched
- {} is not a regular file or symlink
- {} has unsaved directory permission changes; save them befor
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/61bd24c61e5e28cf.
Report an issue: GitHub.