jdx/mise · error
cannot create task stub directory because {} is not a direct
Error message
cannot create task stub directory because {} is not a directory What it means
When generating stubs into nested paths, mise walks each stub's parent directories via `path.ancestors()`. Every existing ancestor must be a real directory (or a regular file that mise already scheduled to migrate into a directory). If an ancestor exists as anything else, mise cannot create the stub there and bails with this message.
Source
Thrown at src/cli/generate/task_stubs.rs:560
"cannot write task stub because {} is not a generated task stub",
display_path(&stub.path)
);
}
}
Ok(_) => bail!(
"cannot write task stub because {} is not a regular file",
display_path(&stub.path)
),
Err(err) if matches!(err.kind(), ErrorKind::NotFound | ErrorKind::NotADirectory) => {}
Err(err) => return Err(err.into()),
}
validate_launcher_path(stub, launchers)?;
for parent in stub.path.ancestors().skip(1) {
match fs::symlink_metadata(parent) {
Ok(metadata)
if metadata.file_type().is_dir()
|| migrations.contains(&StubMigration::File(parent.to_path_buf())) => {}
Ok(_) => bail!(
"cannot create task stub directory because {} is not a directory",
display_path(parent)
),
Err(err)
if matches!(err.kind(), ErrorKind::NotFound | ErrorKind::NotADirectory) => {}
Err(err) => return Err(err.into()),
}
if parent == dir {
break;
}
}
}
Ok(migrations.into_iter().collect())
}
/// Refuse to replace a launcher beside a stub that mise did not write.
///
/// The stub path is the user's choice, so `bin/<task>.cmd` is a name a project may already beView on GitHub (pinned to afd2eddd3a)
Solutions
- Rename or remove the conflicting file/symlink at the ancestor path so the directory can be created.
- Choose a different stub output layout that doesn't collide with existing files.
- Re-run `mise generate task-stubs` after clearing the conflict.
Example fix
// before: .mise/tasks/group is a file, stub wants .mise/tasks/group/build mv .mise/tasks/group .mise/tasks/group.old mkdir -p .mise/tasks/group mv .mise/tasks/group.old .mise/tasks/group/build mise generate task-stubs
Defensive patterns
Strategy: validation
Validate before calling
target = Path('.mise/tasks/group/build')
for parent in target.parents:
if parent.exists() and not parent.is_dir():
raise RuntimeError(f"{parent} blocks directory creation for {target}") Type guard
def ancestors_allow_dir(p: Path) -> bool:
return all(not a.exists() or a.is_dir() for a in p.parents) Prevention
- Avoid naming a flat task file the same as a would-be task group directory
- Plan task layout (flat vs grouped) before generating stubs
- Run `mise tasks ls` to see existing names before choosing grouped stub paths
When it happens
Trigger: Running `mise generate task-stubs` with a stub output like `a/b/task` where `a` exists as a regular file or symlink — so `a/b` cannot be created as a directory.
Common situations: A file occupies the path where a task subdirectory should be (e.g. an old flat task named `group` while generating `group/task`); a symlinked parent directory rejected by the earlier symlink check.
Related errors
- cannot replace task stub directory because {} is empty
- 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
- cannot replace task stub directory because {} does not conta
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/0803c16ed3ad0323.
Report an issue: GitHub.