jdx/mise · error
cannot write Windows launcher because
Error message
cannot write Windows launcher because {} is not a regular file What it means
This error comes from mise's `mise generate task-stub` path validation on Windows. Before writing the Windows `.cmd`/`.ps1` launcher next to a stub, mise stats the launcher path; if it exists but is not a regular file (e.g. it is a directory or symlink), it refuses to overwrite and throws this error. This protects users from clobbering something mise did not generate itself.
Solutions
- Remove or rename the non-regular file (directory/symlink) at the launcher path so mise can write a fresh launcher
- Check what the path is with `Get-Item` / `dir` and restore it to a real file or delete it
- Re-run `mise generate task-stub` after clearing the path
Example fix
// before: launcher path is a directory mkdir stubs\mise-task-build.cmd # blocks launcher creation // after: remove it so mise can generate rmdir stubs\mise-task-build.cmd mise generate task-stub --task build
Defensive patterns
Strategy: validation
Validate before calling
import fs from 'node:fs';
if (fs.existsSync(launcherPath)) {
const st = fs.lstatSync(launcherPath);
if (!st.isFile()) throw new Error(`clear non-file at ${launcherPath} before generating stubs`);
} Type guard
const isRegularFile = (p: string): boolean => { try { return fs.lstatSync(p).isFile(); } catch { return false; } }; Try / catch
try {
await exec('mise generate task-stub ...');
} catch (e) {
if (String(e).includes('is not a regular file')) {
fs.rmSync(launcherPath, { recursive: true }); // after user confirms
}
} Prevention
- Keep stub output directories dedicated to mise-generated files
- Do not create directories or shortcuts at generated launcher paths
- Watch for symlink-manager tools (dotfiles) linking into stub directories
When it happens
Trigger: Running `mise generate task-stub` (Windows) where the computed launcher path for the task already exists as a non-regular file: a directory, a symlink, or a special file at that location. symlink_metadata succeeds, metadata is not file-type regular, so the `Ok(_)` arm bails.
Common situations: A user manually created a directory or shortcut at the launcher path (e.g. `mise-task-foo.cmd` replaced by a folder); a previous tooling run left a symlink there; synced/backup software replaced files with symlinks.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- cannot write Windows launcher because
- cannot write Windows launcher because
- brew import is not supported on windows
- cannot replace task stub directory because
- cannot replace task stub directory because
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/ee9275c096880e06.
Report an issue: GitHub.
Appendix: source
Thrown at src/cli/generate/task_stubs.rs:596
/// The stub path is the user's choice, so `bin/<task>.cmd` is a name a project may already be
/// using for a script of its own — and unlike the stub itself, nothing about the name says mise
/// owns it. `bin/<task>.exe` is the same problem with less to go on, which is why ownership there
/// rests on the bytes. Checked during validation rather than at the write, so a launcher that is
/// not ours stops the whole run instead of leaving a half-generated `bin/`.
fn validate_launcher_path(stub: &TaskStub<'_>, launchers: &Launchers) -> Result<()> {
let Some(launcher) = launchers.path(&stub.path) else {
return Ok(());
};
match fs::symlink_metadata(&launcher) {
Ok(metadata) if metadata.file_type().is_file() => {
if !launchers.owns(&launcher) {
bail!(
"cannot write Windows launcher because {} is not a generated launcher",
display_path(&launcher)
);
}
}
Ok(_) => bail!(
"cannot write Windows launcher because {} is not a regular file",
display_path(&launcher)
),
Err(err) if matches!(err.kind(), ErrorKind::NotFound | ErrorKind::NotADirectory) => {}
Err(err) => return Err(err.into()),
}
Ok(())
}
fn validate_generated_stub_directory(
path: &Path,
expected: &str,
task: &Task,
launchers: &Launchers,
) -> Result<()> {
let default = path.join("_default");
match fs::symlink_metadata(&default) {
Ok(metadata)View on GitHub (pinned to 533346cc37)