jdx/mise · error
cannot replace task stub directory because {} is empty
Error message
cannot replace task stub directory because {} is empty What it means
When replacing a generated stub directory, mise recursively validates its tree. Every subdirectory must contain at least one recognized file (a generated stub, or only mise launchers which count as empty). A subdirectory with no children at all, or one holding only launcher files so it has zero actual stub files, is treated as not a generated tree and mise refuses to proceed.
Source
Thrown at src/cli/generate/task_stubs.rs:636
display_path(path),
task.display_name
),
}
validate_generated_stub_tree(path, launchers)?;
Ok(())
}
fn validate_generated_stub_tree(path: &Path, launchers: &Launchers) -> Result<usize> {
let mut files = 0;
for entry in fs::read_dir(path)? {
let entry = entry?;
let entry_path = entry.path();
let metadata = fs::symlink_metadata(&entry_path)?;
if metadata.file_type().is_dir() {
let child_files = validate_generated_stub_tree(&entry_path, launchers)?;
if child_files == 0 {
bail!(
"cannot replace task stub directory because {} is empty",
display_path(&entry_path)
);
}
files += child_files;
} else if metadata.file_type().is_file() && is_exe_path(&entry_path) {
// A native launcher of ours. Checked before anything reads the file as text, which a
// binary is not. Not counted towards `files`, same as the `.cmd`: a directory holding
// nothing but launchers has no stubs left and should still be reported as empty.
if !launchers.owns(&entry_path) {
bail!(
"cannot replace task stub directory because {} is not a generated task stub",
display_path(&entry_path)
);
}
} else if metadata.file_type().is_file()
&& is_generated_task_stub(&file::read_to_string(&entry_path)?)
{View on GitHub (pinned to afd2eddd3a)
Solutions
- Delete the empty subdirectory (and any launcher-only directories), then re-run `mise generate task-stubs`.
- Back up anything you want to keep from the stub directory tree and remove the whole directory to let mise regenerate.
- Investigate why stubs vanished (partial deletion, sync conflict) before regenerating.
Example fix
// before: .mise/tasks/build/legacy/ is an empty dir rm -rf .mise/tasks/build/legacy mise generate task-stubs // after: directory replaced cleanly
Defensive patterns
Strategy: validation
Validate before calling
for sub in Path('.mise/tasks/build').rglob('*'):
if sub.is_dir() and not any(sub.iterdir()):
print(f"empty subdirectory {sub} will block stub regeneration") Type guard
def no_empty_subdirs(d: Path) -> bool:
return all(any(sub.iterdir()) for sub in d.rglob('*') if sub.is_dir()) Prevention
- Delete empty directories when removing generated stubs, not just the files
- Use mise's own removal/regeneration flow instead of partial manual deletes
- Verify complete syncs when copying tasks trees between machines
When it happens
Trigger: Running `mise generate task-stubs` when a subdirectory inside an existing stub directory is empty, or contains only `.cmd`/native launchers with no generated stub files left.
Common situations: User deleted stub files but left empty directories behind; a failed/partial cleanup removed stubs but not launchers; copying the tasks tree with an incomplete sync tool.
Related errors
- cannot create task stub directory because {} is not a direct
- cannot replace task stub directory because {} does not conta
- cannot write task stub because {} is a symbolic link
- cannot write task stub because {} is not a generated task st
- cannot write task stub because {} is not a regular file
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/4a67845ed48b674e.
Report an issue: GitHub.