{"record":{"id":"0803c16ed3ad0323","repo":"jdx/mise","slug":"cannot-create-task-stub-directory-because-is-no","errorCode":null,"errorMessage":"cannot create task stub directory because {} is not a directory","messagePattern":"cannot create task stub directory because (.+?) is not a directory","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cli/generate/task_stubs.rs","lineNumber":560,"sourceCode":"                        \"cannot write task stub because {} is not a generated task stub\",\n                        display_path(&stub.path)\n                    );\n                }\n            }\n            Ok(_) => bail!(\n                \"cannot write task stub because {} is not a regular file\",\n                display_path(&stub.path)\n            ),\n            Err(err) if matches!(err.kind(), ErrorKind::NotFound | ErrorKind::NotADirectory) => {}\n            Err(err) => return Err(err.into()),\n        }\n        validate_launcher_path(stub, launchers)?;\n        for parent in stub.path.ancestors().skip(1) {\n            match fs::symlink_metadata(parent) {\n                Ok(metadata)\n                    if metadata.file_type().is_dir()\n                        || migrations.contains(&StubMigration::File(parent.to_path_buf())) => {}\n                Ok(_) => bail!(\n                    \"cannot create task stub directory because {} is not a directory\",\n                    display_path(parent)\n                ),\n                Err(err)\n                    if matches!(err.kind(), ErrorKind::NotFound | ErrorKind::NotADirectory) => {}\n                Err(err) => return Err(err.into()),\n            }\n            if parent == dir {\n                break;\n            }\n        }\n    }\n    Ok(migrations.into_iter().collect())\n}\n\n/// Refuse to replace a launcher beside a stub that mise did not write.\n///\n/// The stub path is the user's choice, so `bin/<task>.cmd` is a name a project may already be","sourceCodeStart":542,"sourceCodeEnd":578,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/cli/generate/task_stubs.rs#L542-L578","documentation":"When generating stubs into nested paths, mise walks each stub's parent directories via `path.ancestors()`. Every existing ancestor must be a real directory (or a regular file that mise already scheduled to migrate into a directory). If an ancestor exists as anything else, mise cannot create the stub there and bails with this message.","triggerScenarios":"Running `mise generate task-stubs` with a stub output like `a/b/task` where `a` exists as a regular file or symlink — so `a/b` cannot be created as a directory.","commonSituations":"A file occupies the path where a task subdirectory should be (e.g. an old flat task named `group` while generating `group/task`); a symlinked parent directory rejected by the earlier symlink check.","solutions":["Rename or remove the conflicting file/symlink at the ancestor path so the directory can be created.","Choose a different stub output layout that doesn't collide with existing files.","Re-run `mise generate task-stubs` after clearing the conflict."],"exampleFix":"// before: .mise/tasks/group is a file, stub wants .mise/tasks/group/build\nmv .mise/tasks/group .mise/tasks/group.old\nmkdir -p .mise/tasks/group\nmv .mise/tasks/group.old .mise/tasks/group/build\nmise generate task-stubs","handlingStrategy":"validation","validationCode":"target = Path('.mise/tasks/group/build')\nfor parent in target.parents:\n    if parent.exists() and not parent.is_dir():\n        raise RuntimeError(f\"{parent} blocks directory creation for {target}\")","typeGuard":"def ancestors_allow_dir(p: Path) -> bool:\n    return all(not a.exists() or a.is_dir() for a in p.parents)","tryCatchPattern":null,"preventionTips":["Avoid naming a flat task file the same as a would-be task group directory","Plan task layout (flat vs grouped) before generating stubs","Run `mise tasks ls` to see existing names before choosing grouped stub paths"],"tags":["filesystem","task-stubs","path-conflict","directory"],"backgroundTag":"path-is-not-a-directory","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}