jdx/mise · error
[dotfiles]."{req.target_raw}": mode symlink-each requires a
Error message
[dotfiles]."{req.target_raw}": mode symlink-each requires a directory source: {req.source.display} What it means
The `symlink-each` dotfile mode creates one symlink per child entry of the source, so the source must be a directory. If the source is a regular file (or other non-directory), mise rejects the entry because per-entry symlinking is undefined for a single file.
Source
Thrown at src/oci/builder.rs:950
"[dotfiles].\"{}\": source does not exist: {}",
req.target_raw,
req.source.display()
);
}
match req.mode {
// a tracked file lives on the machine that tracks it; an image
// has nothing to copy
FileMode::Track => continue,
FileMode::Symlink | FileMode::Copy => {
collect_source_as_files(&req.source, &oci_target_path(req)?, &mut entries)
.wrap_err_with(|| {
format!("adding [dotfiles].\"{}\" to OCI image", req.target_raw)
})?;
}
FileMode::SymlinkEach => {
if !req.source.is_dir() {
bail!(
"[dotfiles].\"{}\": mode symlink-each requires a directory source: {}",
req.target_raw,
req.source.display()
);
}
let target = oci_target_path(req)?;
entries.add_dir(target.clone())?;
for entry in walkdir::WalkDir::new(&req.source).sort_by_file_name() {
let entry = entry?;
let ft = entry.file_type();
if !(ft.is_file() || ft.is_symlink()) {
continue;
}
let rel = entry.path().strip_prefix(&req.source)?;
let path = format!("{target}/{}", rel.to_string_lossy().replace('\\', "/"));
entries.add_file(
path,
file::read(entry.path())?,View on GitHub (pinned to afd2eddd3a)
Solutions
- Change the mode to `symlink` or `copy` for single-file sources.
- Point `source` at the directory whose children should each be symlinked.
- Split the entry: use `symlink-each` for the directory and a separate `symlink`/`content` entry for individual files.
Example fix
# before [dotfiles."/root/.config"] source = "~/.gitconfig" mode = "symlink-each" # after [dotfiles."/root/.gitconfig"] source = "~/.gitconfig" mode = "symlink"
Defensive patterns
Strategy: validation
Validate before calling
if (req.mode === 'symlink-each' && !fs.statSync(req.source).isDirectory()) {
throw new Error(`symlink-each requires a directory source: ${req.source}`);
} Type guard
const isDir = (p) => { try { return fs.statSync(p).isDirectory(); } catch { return false; } }; Prevention
- Reserve `symlink-each` for directories; use `symlink`/`copy` for single files.
- When converting a dotfiles directory into individual files, update the mode accordingly.
- Check sources with `test -d` in pre-build scripts.
When it happens
Trigger: `[dotfiles]."target"` entry with `mode = "symlink-each"` whose `source` points at a file instead of a directory — commonly after changing a directory source into a single file, or a typo pointing at a sibling file.
Common situations: Pointing symlink-each at `~/.config/foo.conf` intending to symlink it; refactoring a dotfiles dir into individual files while keeping the old mode; a symlink-each source that is itself a symlink to a file.
Related errors
- [dotfiles]."{}": mode symlink-each requires a directory sour
- dotfiles: {key} could not be tracked: {reason}
- "{path_raw}".{id}: block/source and line are mutually exclus
- "{path_raw}".{id}: no recognized operation (block, source, o
- "{path_raw}".{id}: position is only valid with line, ignorin
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/ebaac092374524ad.
Report an issue: GitHub.