jdx/mise · error

cannot write Windows launcher because

Error message

cannot write Windows launcher because {} is not a generated launcher

What it means

In `mise generate tool-stub` on Windows, mise writes a companion Windows launcher file. If the launcher path already exists as a regular file but its content fails the `is_generated_launcher` check, mise bails with this error rather than overwriting a file it did not generate. This prevents overwriting user files that happen to occupy the launcher path.

Solutions

  1. Remove or rename the existing file at the launcher path and re-run generation
  2. Inspect the file's content; if it's a stale mise launcher, delete it so a fresh one is written
  3. Generate into a clean dedicated output path

Example fix

// before: custom script occupies launcher path
stubs\tool.cmd  # user-written, not generated -> bail
// after
mv stubs\tool.cmd .\scripts\
mise generate tool-stub --url https://example.com/tool
Defensive patterns

Strategy: validation

Validate before calling

if (fs.existsSync(launcherPath) && fs.lstatSync(launcherPath).isFile()) {
  const content = fs.readFileSync(launcherPath, 'utf8');
  if (!content.includes('generated by mise')) throw new Error('non-generated file at launcher path');
}

Try / catch

try {
  await exec('mise generate tool-stub ...');
} catch (e) {
  if (String(e).includes('is not a generated launcher')) {
    fs.renameSync(launcherPath, launcherPath + '.bak');
    await exec('mise generate tool-stub ...');
  }
}

Prevention

When it happens

Trigger: Running `mise generate tool-stub` where the computed Windows launcher path exists as a regular file whose content is not a mise-generated launcher — e.g. a user-created script, a downloaded binary, or a launcher from another tool.

Common situations: Users placed their own script at the launcher path; stubs were generated into a directory shared with other tools; an older mise's launcher format no longer matches the current generated marker.

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


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/40b086e57ff3f393. Report an issue: GitHub.

Appendix: source

Thrown at src/cli/generate/tool_stub.rs:237

        Ok(None)
    }

    /// Refuse to replace a `.cmd` beside the stub that mise did not write.
    ///
    /// `--output` is the user's choice, so `<stub>.cmd` is a name a project may already be using
    /// for a script of its own, and nothing about that name says mise owns it. The stub itself is
    /// different: the user named it, so overwriting it is what they asked for.
    fn validate_windows_launcher(&self, stub_content: &str) -> Result<()> {
        if !wants_windows_launcher(stub_content) {
            return Ok(());
        }
        let Some(launcher) = super::windows_launcher_path(&self.output) else {
            return Ok(());
        };
        match fs::symlink_metadata(&launcher) {
            Ok(metadata) if metadata.file_type().is_file() => {
                if !super::is_generated_launcher(&file::read_to_string(&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 get_tool_name(&self) -> String {
        self.output
            .file_name()

View on GitHub (pinned to 533346cc37)