jdx/mise · error

cannot write task stub because

Error message

cannot write task stub because {} is not a generated task stub

What it means

mise only overwrites an existing file at a task stub path if its content matches generated stub output (current or legacy format). This error means the file at the stub path has unrecognized content, so mise assumes it is a hand-written file and refuses to clobber it.

Solutions

  1. Delete the file at the stub path (after saving any manual changes elsewhere) and rerun generation
  2. Revert manual edits so the content matches the previously generated stub output
  3. Stop generating stubs for that task and keep the hand-written file as the task entry point

Example fix

// before: hand-edited stub
#!/bin/sh
exec mise x -- build "$@" # tweaked
// after
mv .mise/tasks/build ~/backup/ && mise generate task-stubs
Defensive patterns

Strategy: validation

Validate before calling

const existing = fs.readFileSync(stubPath, 'utf8');
if (existing !== generatedOutput && existing !== legacyOutput) {
  throw new Error(`${stubPath} is not a generated stub; back it up and remove before regenerating`);
}

Try / catch

try {
  execSync('mise generate task-stubs');
} catch (e) {
  if (String(e).includes('is not a generated task stub')) {
    console.error('File was hand-modified or foreign; preserve it, remove, regenerate');
  }
}

Prevention

When it happens

Trigger: Running `mise generate task-stubs` after a generated stub was manually edited, or where a user's own script exists at the stub path, or where stub output format changed without matching either known template.

Common situations: Hand edits to committed stubs that then drift from the generator; upgrading mise after stub template changes; users placing real task scripts at paths the generator wants to own.

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/e6086c7609ae02e1. Report an issue: GitHub.

Appendix: source

Thrown at src/cli/generate/task_stubs.rs:541

            Err(err) => return Err(err.into()),
        }
    }

    for stub in stubs {
        match fs::symlink_metadata(&stub.path) {
            Ok(metadata) if metadata.file_type().is_dir() => {
                validate_generated_stub_directory(&stub.path, &stub.output, stub.task, launchers)?;
                migrations.insert(StubMigration::Directory(stub.path.clone()));
            }
            Ok(metadata) if metadata.file_type().is_symlink() => bail!(
                "cannot write task stub because {} is a symbolic link",
                display_path(&stub.path)
            ),
            Ok(metadata) if metadata.file_type().is_file() => {
                let existing = file::read_to_string(&stub.path)?;
                let legacy_leaf = stub.legacy_path == stub.path && existing == stub.legacy_output;
                if existing != stub.output && !legacy_leaf {
                    bail!(
                        "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())) => {}

View on GitHub (pinned to 533346cc37)