{"record":{"id":"ee9275c096880e06","repo":"jdx/mise","slug":"cannot-write-windows-launcher-because-is-not-a-ee9275","errorCode":null,"errorMessage":"cannot write Windows launcher because {} is not a regular file","messagePattern":"cannot write Windows launcher because (.+?) is not a regular file","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cli/generate/task_stubs.rs","lineNumber":596,"sourceCode":"/// The stub path is the user's choice, so `bin/<task>.cmd` is a name a project may already be\n/// using for a script of its own — and unlike the stub itself, nothing about the name says mise\n/// owns it. `bin/<task>.exe` is the same problem with less to go on, which is why ownership there\n/// rests on the bytes. Checked during validation rather than at the write, so a launcher that is\n/// not ours stops the whole run instead of leaving a half-generated `bin/`.\nfn validate_launcher_path(stub: &TaskStub<'_>, launchers: &Launchers) -> Result<()> {\n    let Some(launcher) = launchers.path(&stub.path) else {\n        return Ok(());\n    };\n    match fs::symlink_metadata(&launcher) {\n        Ok(metadata) if metadata.file_type().is_file() => {\n            if !launchers.owns(&launcher) {\n                bail!(\n                    \"cannot write Windows launcher because {} is not a generated launcher\",\n                    display_path(&launcher)\n                );\n            }\n        }\n        Ok(_) => bail!(\n            \"cannot write Windows launcher because {} is not a regular file\",\n            display_path(&launcher)\n        ),\n        Err(err) if matches!(err.kind(), ErrorKind::NotFound | ErrorKind::NotADirectory) => {}\n        Err(err) => return Err(err.into()),\n    }\n    Ok(())\n}\n\nfn validate_generated_stub_directory(\n    path: &Path,\n    expected: &str,\n    task: &Task,\n    launchers: &Launchers,\n) -> Result<()> {\n    let default = path.join(\"_default\");\n    match fs::symlink_metadata(&default) {\n        Ok(metadata)","sourceCodeStart":578,"sourceCodeEnd":614,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/cli/generate/task_stubs.rs#L578-L614","documentation":"This error comes from mise's `mise generate task-stub` path validation on Windows. Before writing the Windows `.cmd`/`.ps1` launcher next to a stub, mise stats the launcher path; if it exists but is not a regular file (e.g. it is a directory or symlink), it refuses to overwrite and throws this error. This protects users from clobbering something mise did not generate itself.","triggerScenarios":"Running `mise generate task-stub` (Windows) where the computed launcher path for the task already exists as a non-regular file: a directory, a symlink, or a special file at that location. symlink_metadata succeeds, metadata is not file-type regular, so the `Ok(_)` arm bails.","commonSituations":"A user manually created a directory or shortcut at the launcher path (e.g. `mise-task-foo.cmd` replaced by a folder); a previous tooling run left a symlink there; synced/backup software replaced files with symlinks.","solutions":["Remove or rename the non-regular file (directory/symlink) at the launcher path so mise can write a fresh launcher","Check what the path is with `Get-Item` / `dir` and restore it to a real file or delete it","Re-run `mise generate task-stub` after clearing the path"],"exampleFix":"// before: launcher path is a directory\nmkdir stubs\\mise-task-build.cmd   # blocks launcher creation\n// after: remove it so mise can generate\nrmdir stubs\\mise-task-build.cmd\nmise generate task-stub --task build","handlingStrategy":"validation","validationCode":"import fs from 'node:fs';\nif (fs.existsSync(launcherPath)) {\n  const st = fs.lstatSync(launcherPath);\n  if (!st.isFile()) throw new Error(`clear non-file at ${launcherPath} before generating stubs`);\n}","typeGuard":"const isRegularFile = (p: string): boolean => { try { return fs.lstatSync(p).isFile(); } catch { return false; } };","tryCatchPattern":"try {\n  await exec('mise generate task-stub ...');\n} catch (e) {\n  if (String(e).includes('is not a regular file')) {\n    fs.rmSync(launcherPath, { recursive: true }); // after user confirms\n  }\n}","preventionTips":["Keep stub output directories dedicated to mise-generated files","Do not create directories or shortcuts at generated launcher paths","Watch for symlink-manager tools (dotfiles) linking into stub directories"],"tags":["windows","launcher","file-conflict","cli"],"backgroundTag":"file-already-exists","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"}