jdx/mise · error

cannot create task stub directory because

Error message

cannot create task stub directory because {} is not a directory

What it means

When creating nested task stubs, mise walks every ancestor directory of each stub path and requires each to be a real directory (or a legacy stub file queued for migration into a directory). This error means an ancestor exists as a non-directory file, so the stub's directory structure cannot be created.

Solutions

  1. Remove or rename the file occupying the intermediate path so mise can create the directory
  2. Ensure the file is recognized as a legacy generated stub (its content must match generated output) so it gets migrated
  3. Restructure task names/paths so nested components don't collide with existing files

Example fix

// before
.mise/tasks/build  # regular file, but build/x needs build/ to be a directory
// after
rm .mise/tasks/build && mise generate task-stubs
Defensive patterns

Strategy: validation

Validate before calling

for (const parent of ancestorsOf(stubPath)) {
  const st = fs.lstatSync(parent, { throwIfNoEntry: false });
  if (st && !st.isDirectory()) {
    throw new Error(`${parent} blocks directory creation; remove or migrate it first`);
  }
}

Try / catch

try {
  execSync('mise generate task-stubs');
} catch (e) {
  if (String(e).includes('is not a directory')) {
    console.error('A path component exists as a file; remove/rename it and rerun');
  }
}

Prevention

When it happens

Trigger: Running `mise generate task-stubs` with nested stub paths where an intermediate path component exists as a regular file, e.g. a file named `.mise/tasks` or a file where a subdirectory like `tasks/build` is needed.

Common situations: A previously generated flat stub file occupies a path that nested layout now needs as a directory but which was not recognized as a migratable stub; users created a file with the same name as a planned subdirectory.

Related errors


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

Appendix: source

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

                        "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())) => {}
                Ok(_) => bail!(
                    "cannot create task stub directory because {} is not a directory",
                    display_path(parent)
                ),
                Err(err)
                    if matches!(err.kind(), ErrorKind::NotFound | ErrorKind::NotADirectory) => {}
                Err(err) => return Err(err.into()),
            }
            if parent == dir {
                break;
            }
        }
    }
    Ok(migrations.into_iter().collect())
}

/// Refuse to replace a launcher beside a stub that mise did not write.
///
/// The stub path is the user's choice, so `bin/<task>.cmd` is a name a project may already be

View on GitHub (pinned to 533346cc37)