jdx/mise · error

cannot replace task stub directory because {} is not a gener

Error message

cannot replace task stub directory because {} is not a generated task stub

What it means

Walking a stub directory mise intends to replace, an entry is neither a generated stub (first lines `#!/bin/sh` then `# generated by mise task-stubs`) nor a generated Windows launcher (`@echo off` + `rem generated by mise`). One foreign file means the directory is not purely mise's output, so mise refuses to replace it — deleting it could destroy user data.

Source

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

            let child_files = validate_generated_stub_tree(&entry_path)?;
            if child_files == 0 {
                bail!(
                    "cannot replace task stub directory because {} is empty",
                    display_path(&entry_path)
                );
            }
            files += child_files;
        } else if metadata.file_type().is_file()
            && is_generated_task_stub(&file::read_to_string(&entry_path)?)
        {
            files += 1;
        } else if metadata.file_type().is_file()
            && super::is_generated_launcher(&file::read_to_string(&entry_path)?)
        {
            // Our own Windows launcher. Not counted towards `files`: a directory holding nothing
            // but launchers has no stubs left and should still be reported as empty.
        } else {
            bail!(
                "cannot replace task stub directory because {} is not a generated task stub",
                display_path(&entry_path)
            );
        }
    }
    Ok(files)
}

fn is_generated_task_stub(contents: &str) -> bool {
    let mut lines = contents.lines();
    matches!(lines.next(), Some("#!/bin/sh"))
        && matches!(lines.next(), Some("# generated by mise task-stubs"))
        && lines
            .next()
            .and_then(|line| line.strip_prefix("exec "))
            .and_then(|line| line.strip_suffix(" \"$@\""))
            .is_some_and(|line| line.contains(" run "))
        && lines.next().is_none()

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Move or remove the foreign file named in the error: `git rm bin/<parent>/<file>`
  2. Rerun `mise generate task-stubs`
  3. Keep build outputs out of the stub dir (.gitignore, out-of-tree build paths) so they do not return

Example fix

# before
$ mise generate task-stubs
# error: bin/build/notes.md is not a generated task stub

# after
$ git rm bin/build/notes.md
$ mise generate task-stubs
Defensive patterns

Strategy: type-guard

Validate before calling

#!/bin/bash
# every file in a stub directory must be a generated stub or launcher
while IFS= read -r -d '' f; do
  is_mise_stub "$f" || is_mise_launcher "$f" || { echo "foreign file: $f" >&2; exit 1; }
done < <(find bin -type f -print0)
mise generate task-stubs

Type guard

is_mise_stub() {
  [ "$(head -1 "$1")" = '#!/bin/sh' ] && [ "$(sed -n 2p "$1")" = '# generated by mise task-stubs' ]
}
is_mise_launcher() {
  [ "$(head -1 "$1")" = '@echo off' ] && [ "$(sed -n 2p "$1")" = 'rem generated by mise' ]
}

Try / catch

if ! mise generate task-stubs; then
  echo 'foreign file inside stub directory — move it out (e.g. to scripts/) and rerun' >&2
  exit 1
fi

Prevention

When it happens

Trigger: Any extra file inside bin/<parent>/ — notes, compiled artifacts, cache files, a hand script — while the nested-stub migration for that directory is pending.

Common situations: Build outputs written into bin/; developers storing scratch files under the stub directory; tools seeding .gitkeep-with-content.

Related errors


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