jdx/mise · error

cannot write Windows launcher because {} is not a generated

Error message

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

What it means

`mise generate tool-stub --output <file>` writes a `<file>.cmd` launcher beside the shebang stub so Windows can run it (CreateProcess will not execute shebang scripts). That launcher path already holds a regular file that is not a mise-generated launcher (must be `@echo off` + `rem generated by mise` + one line ending in ` %*`). Since nothing about the name says mise owns it, mise refuses to overwrite it; validation runs before the stub is written so the run fails without partial output.

Source

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

        Ok(())
    }

    /// 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 9dcfcaa0dc)

Solutions

  1. If the .cmd is hand-written, rename it (`git mv bin/mytool.cmd bin/mytool-run.cmd`) or relocate its logic
  2. If it is a stale generated launcher you no longer want, delete it and rerun
  3. Choose an `--output` name whose `.cmd` sibling is free

Example fix

# before
$ mise generate tool-stub --output bin/kubectl --url https://...
# error: bin/kubectl.cmd is not a generated launcher

# after
$ git mv bin/kubectl.cmd scripts/kubectl.cmd
$ mise generate tool-stub --output bin/kubectl --url https://...
Defensive patterns

Strategy: type-guard

Validate before calling

#!/bin/bash
OUT=bin/mytool
if [ -e "$OUT.cmd" ] && [ -f "$OUT.cmd" ]; then
  is_mise_launcher "$OUT.cmd" || { echo "$OUT.cmd is hand-written — rename it first" >&2; exit 1; }
fi
mise generate tool-stub --output "$OUT" --url "$URL"

Type guard

is_mise_launcher() {
  [ "$(head -1 "$1")" = '@echo off' ] && [ "$(sed -n 2p "$1")" = 'rem generated by mise' ] && [ "$(tail -1 "$1")" = "$(tail -1 "$1" | sed 's/.* //')" ]
}

Try / catch

if ! mise generate tool-stub --output bin/mytool --url "$URL"; then
  [ -f bin/mytool.cmd ] && echo 'bin/mytool.cmd is not generated — rename or remove it, then rerun' >&2
  exit 1
fi

Prevention

When it happens

Trigger: `mise generate tool-stub --output bin/mytool --url ...` when bin/mytool.cmd is a project-authored batch script, or an old launcher that was edited beyond recognition.

Common situations: Repo already ships bin/<name>.cmd wrappers; Windows CI scripts sharing the stub's base name; stub regenerated after someone customized the .cmd.

Related errors


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