{"record":{"id":"4a67845ed48b674e","repo":"jdx/mise","slug":"cannot-replace-task-stub-directory-because-is-e","errorCode":null,"errorMessage":"cannot replace task stub directory because {} is empty","messagePattern":"cannot replace task stub directory because (.+?) is empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cli/generate/task_stubs.rs","lineNumber":636,"sourceCode":"            display_path(path),\n            task.display_name\n        ),\n    }\n\n    validate_generated_stub_tree(path, launchers)?;\n    Ok(())\n}\n\nfn validate_generated_stub_tree(path: &Path, launchers: &Launchers) -> Result<usize> {\n    let mut files = 0;\n    for entry in fs::read_dir(path)? {\n        let entry = entry?;\n        let entry_path = entry.path();\n        let metadata = fs::symlink_metadata(&entry_path)?;\n        if metadata.file_type().is_dir() {\n            let child_files = validate_generated_stub_tree(&entry_path, launchers)?;\n            if child_files == 0 {\n                bail!(\n                    \"cannot replace task stub directory because {} is empty\",\n                    display_path(&entry_path)\n                );\n            }\n            files += child_files;\n        } else if metadata.file_type().is_file() && is_exe_path(&entry_path) {\n            // A native launcher of ours. Checked before anything reads the file as text, which a\n            // binary is not. Not counted towards `files`, same as the `.cmd`: a directory holding\n            // nothing but launchers has no stubs left and should still be reported as empty.\n            if !launchers.owns(&entry_path) {\n                bail!(\n                    \"cannot replace task stub directory because {} is not a generated task stub\",\n                    display_path(&entry_path)\n                );\n            }\n        } else if metadata.file_type().is_file()\n            && is_generated_task_stub(&file::read_to_string(&entry_path)?)\n        {","sourceCodeStart":618,"sourceCodeEnd":654,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/cli/generate/task_stubs.rs#L618-L654","documentation":"When validating a stub directory tree before replacement, mise recursively counts generated stub files. If a subdirectory contains no countable generated stubs at all (it is empty or holds only launchers, which are not counted), mise bails with this error rather than deleting an empty directory during replacement.","triggerScenarios":"Running `mise generate task-stub` against an output directory containing an empty subdirectory, or a subdirectory whose only files are Windows launchers/`.cmd` files (explicitly excluded from the stub count).","commonSituations":"User manually cleaned out a subfolder of stubs but left the folder; a previous partial generation left a launcher-only directory; git checkout or sync tooling pruned stub files but kept directories.","solutions":["Delete the empty subdirectory before re-running generation","Place a valid generated task stub in the subdirectory","Regenerate into a fresh output directory"],"exampleFix":"// before: stubs\\nested\\ exists but is empty\nmkdir -p stubs\\nested\nmise generate task-stub --output stubs   # fails\n// after\nrmdir stubs\\nested\nmise generate task-stub --output stubs","handlingStrategy":"validation","validationCode":"const hasEmptySubdir = (dir: string): boolean =>\n  fs.readdirSync(dir, { withFileTypes: true, recursive: true })\n    .some(d => d.isDirectory() && fs.readdirSync(path.join(d.parentPath ?? dir, d.name)).length === 0);","typeGuard":null,"tryCatchPattern":"try {\n  await exec('mise generate task-stub ...');\n} catch (e) {\n  if (String(e).includes('is empty')) {\n    // remove empty subdirectories then retry\n    await exec('find ' + stubDir + ' -type d -empty -delete');\n    await exec('mise generate task-stub ...');\n  }\n}","preventionTips":["Delete empty subfolders from stub output directories before regenerating","Never leave launcher-only directories when cleaning stubs","Regenerate into a fresh directory instead of mutating a partially-cleaned tree"],"tags":["windows","task-stub","validation","empty-directory"],"backgroundTag":"directory-not-found","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}