jdx/mise · error

cannot create nested task stubs because {} is not a director

Error message

cannot create nested task stubs because {} is not a directory

What it means

While migrating a task to the nested layout, the legacy path exists but is neither a regular file nor a directory (fifo, socket, device node). The migration only knows how to replace its own file or descend through a directory, so it refuses rather than destroy an unknown object.

Source

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

}

fn validate_stub_paths(dir: &Path, stubs: &[TaskStub<'_>]) -> Result<Vec<StubMigration>> {
    let mut migrations = HashSet::new();
    for stub in stubs.iter().filter(|stub| stub.legacy_path != stub.path) {
        match fs::symlink_metadata(&stub.legacy_path) {
            Ok(metadata) if metadata.file_type().is_file() => {
                let existing = file::read_to_string(&stub.legacy_path)?;
                if existing != stub.output && existing != stub.legacy_output {
                    bail!(
                        "cannot create nested task stubs because {} is not the generated stub for task {}",
                        display_path(&stub.legacy_path),
                        stub.task.display_name
                    );
                }
                migrations.insert(StubMigration::File(stub.legacy_path.clone()));
            }
            Ok(metadata) if metadata.file_type().is_dir() => {}
            Ok(_) => bail!(
                "cannot create nested task stubs because {} is not a directory",
                display_path(&stub.legacy_path)
            ),
            Err(err) if matches!(err.kind(), ErrorKind::NotFound | ErrorKind::NotADirectory) => {}
            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)?;
                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)
            ),

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Remove the special file: `rm bin/<legacy path>`
  2. Regenerate into a clean directory (`mise generate task-stubs --dir bin2`) and swap it in
  3. If something must keep that name, rename the task

Example fix

# before
$ ls -l bin/build   # shows pipe/socket type
$ mise generate task-stubs
# error: bin/build is not a directory

# after
$ rm bin/build
$ mise generate task-stubs
Defensive patterns

Strategy: type-guard

Validate before calling

#!/bin/bash
# only regular files and directories may exist under the stub dir
find bin -mindepth 1 ! -type d ! -type f -print -quit | grep -q . \
  && { echo 'special file under bin/' >&2; exit 1; }
mise generate task-stubs

Type guard

is_plain_fs_object() {
  # 0 when path is absent, a regular file, or a directory
  [ -e "$1" ] || return 0
  [ -f "$1" ] || [ -d "$1" ]
}

Prevention

When it happens

Trigger: A named pipe, socket, or device sits at bin/<legacy path> when `mise generate task-stubs` runs with a parent/nested task pair present.

Common situations: Dev leftovers in bin/ (mkfifo experiments), odd container image contents, bind mounts exposing special files into the stub directory.

Related errors


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