Repository navigation
fix(task): improve error message when task files are not executable - #8705
Conversation
When task files exist in mise-tasks/ but lack the executable bit (common when created on Windows), show a clear error with chmod +x instructions instead of the generic "no tasks defined" message. Closes #8614 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the user experience for Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
Greptile SummaryThis PR improves the UX for a common Windows→macOS/Linux workflow issue: when task files exist in Key changes:
Minor remaining polish item (not blocking): the space-joined file paths in the Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[User runs mise run <task> or mise tasks] --> B{Tasks found?}
B -- Yes --> C[Execute / list tasks normally]
B -- No / empty --> D{Platform Windows?}
D -- Yes --> E[Generic error: no tasks defined]
D -- No --> F[find_non_executable_task_files]
F --> G{Non-executable files exist in include dirs?}
G -- No --> E
G -- Yes --> H{Called from err_no_task?}
H -- Yes, mise run --> I[bail! with count + dir list + chmod +x suggestion]
H -- No, mise tasks ls --> J[warn! about non-executable files + chmod +x hint]
Reviews (5): Last reviewed commit: "fix(task): allow hidden root dirs like ...." | Re-trigger Greptile |
There was a problem hiding this comment.
Code Review
This pull request improves the user experience by providing a more informative error message when task files are not executable, which is a common issue for users moving between Windows and Unix-like systems. The changes include a new e2e test to cover this scenario, a warning in mise tasks ls, and a detailed error in mise run. The implementation is solid, but I've suggested a small refactoring to improve performance and code clarity in one of the new code blocks.
| let non_exec_files: Vec<PathBuf> = includes | ||
| .iter() | ||
| .filter(|d| d.is_dir()) | ||
| .flat_map(|d| { | ||
| walkdir::WalkDir::new(d) | ||
| .into_iter() | ||
| .filter_map(|e| e.ok()) | ||
| .filter(|e| e.file_type().is_file()) | ||
| .map(|e| e.path().to_path_buf()) | ||
| .filter(|p| !file::is_executable(p)) | ||
| .collect::<Vec<_>>() | ||
| }) | ||
| .collect(); | ||
| if !non_exec_files.is_empty() { | ||
| let dirs_with_files: Vec<String> = includes | ||
| .iter() | ||
| .filter(|d| d.is_dir()) | ||
| .map(|d| display_path(d)) | ||
| .collect(); | ||
| bail!( | ||
| "no tasks defined in {}, but found {} non-executable file(s) in {}.\n\ | ||
| Files must be executable to be detected as tasks.\n\ | ||
| Run `chmod +x` on the task files to fix this, e.g.:\n chmod +x {}", | ||
| display_path(dirs::CWD.clone().unwrap_or_default()), | ||
| non_exec_files.len(), | ||
| dirs_with_files.join(", "), | ||
| non_exec_files | ||
| .iter() | ||
| .take(5) | ||
| .map(|p| display_path(p)) | ||
| .collect::<Vec<_>>() | ||
| .join(" "), | ||
| ); |
There was a problem hiding this comment.
This logic for finding non-executable files can be made more efficient and readable.
- The iterator chain for finding non-executable files collects into a
Vecfor each subdirectory inside theflat_map, which is inefficient. This can be avoided by chaining iterators directly and letting the finalcollectdo the work. - The
bail!macro can use thecwdvariable that is already in scope, which is a minor cleanup.
I've combined these improvements in the suggestion below.
Additionally, this logic is very similar to the one in src/cli/tasks/ls.rs. Consider extracting it into a shared helper function in a future refactoring to avoid code duplication.
let non_exec_files: Vec<PathBuf> = includes
.iter()
.filter(|d| d.is_dir())
.flat_map(|d| {
walkdir::WalkDir::new(d)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.file_type().is_file() && !file::is_executable(e.path()))
.map(|e| e.path().to_path_buf())
})
.collect();
if !non_exec_files.is_empty() {
let dirs_with_files: Vec<String> = includes
.iter()
.filter(|d| d.is_dir())
.map(|d| display_path(d))
.collect();
bail!(
"no tasks defined in {}, but found {} non-executable file(s) in {}.\n\
Files must be executable to be detected as tasks.\n\
Run `chmod +x` on the task files to fix this, e.g.:\n chmod +x {}",
display_path(cwd),
non_exec_files.len(),
dirs_with_files.join(", "),
non_exec_files
.iter()
.take(5)
.map(|p| display_path(p))
.collect::<Vec<_>>()
.join(" "),
);Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Skip hidden files (e.g., .gitkeep, .DS_Store) when scanning for non-executable task files, matching the behavior of load_tasks_includes - Check unfiltered task count in `mise tasks ls` so the warning doesn't fire when tasks exist but are filtered by --hidden/--local/--global Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
cf42dcf to
2523b69
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
The filter_entry was skipping all entries starting with '.', including the WalkDir root itself. This meant .mise-tasks/ contents were never scanned. Match load_tasks_includes behavior by exempting the root. Also add chmod +x assertion to mise tasks warning test. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
| non_exec_files | ||
| .iter() | ||
| .take(5) | ||
| .map(display_path) | ||
| .collect::<Vec<_>>() | ||
| .join(" "), |
There was a problem hiding this comment.
Unquoted paths in
chmod +x example
File paths are joined with a plain space: if any task file has a space in its name (e.g. mise-tasks/my build), the generated chmod +x command would be ambiguous and incorrect at the shell. Consider wrapping each path in double-quotes:
| non_exec_files | |
| .iter() | |
| .take(5) | |
| .map(display_path) | |
| .collect::<Vec<_>>() | |
| .join(" "), | |
| non_exec_files | |
| .iter() | |
| .take(5) | |
| .map(|p| format!("\"{}\"", display_path(p))) | |
| .collect::<Vec<_>>() | |
| .join(" "), |
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.10 x -- echo |
18.9 ± 0.8 | 17.5 | 22.1 | 1.00 |
mise x -- echo |
18.9 ± 0.6 | 17.7 | 24.2 | 1.00 ± 0.05 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.10 env |
18.3 ± 0.7 | 17.1 | 23.2 | 1.00 |
mise env |
19.5 ± 0.7 | 17.8 | 22.6 | 1.06 ± 0.06 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.10 hook-env |
20.7 ± 0.3 | 19.7 | 23.8 | 1.00 |
mise hook-env |
21.3 ± 2.1 | 20.4 | 59.0 | 1.03 ± 0.10 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.10 ls |
19.4 ± 0.7 | 18.0 | 21.4 | 1.00 ± 0.05 |
mise ls |
19.4 ± 0.6 | 17.8 | 21.5 | 1.00 |
xtasks/test/perf
| Command | mise-2026.3.10 | mise | Variance |
|---|---|---|---|
| install (cached) | 116ms | 114ms | +1% |
| ls (cached) | 69ms | 69ms | +0% |
| bin-paths (cached) | 69ms | 69ms | +0% |
| task-ls (cached) | 746ms | 718ms | +3% |
### 🚀 Features - **(github)** read tokens from gh CLI hosts.yml config by @jdx in [#8692](#8692) - **(task)** support optional `args` and `env` fields in `run` entries by @jdx in [#8687](#8687) - **(task)** add --skip-tools flag to mise run by @jdx in [#8699](#8699) - **(vfox)** add try_get, try_head, try_download_file to Lua HTTP module by @jdx in [#8697](#8697) ### 🐛 Bug Fixes - **(config)** recognize SSH and other non-HTTPS URLs in get_repo_url by @modestman in [#8666](#8666) - **(docs)** add dark mode support to favicon by @jdx in [#8678](#8678) - **(env)** support multiple --env/-E flags by @jdx in [#8686](#8686) - **(github)** rename_exe renames correct binary when archive contains multiple executables by @jdx in [#8700](#8700) - **(implode)** include system data dir in implode cleanup by @jdx in [#8696](#8696) - **(install)** skip GitHub API calls for aqua tools in --locked mode by @jdx in [#8679](#8679) - **(install)** skip redundant provenance verification when lockfile has integrity data by @jdx in [#8688](#8688) - **(lock)** respect existing platforms in lockfile when running `mise lock` by @jdx in [#8708](#8708) - **(lock)** skip global config lockfile by default by @jdx in [#8707](#8707) - **(node)** expand tilde in default_packages_file path by @jdx in [#8709](#8709) - **(shell)** error when no version specified instead of silent no-op by @jdx in [#8693](#8693) - **(shim)** detect shims by checking shims directory instead of binary name by @jdx in [#8694](#8694) - **(task)** inherit task_config.dir for included TOML and file tasks by @jdx in [#8689](#8689) - **(task)** strip inline args when validating run.tasks references by @jdx in [#8701](#8701) - **(task)** include idiomatic version files in monorepo task toolset by @jdx in [#8702](#8702) - **(task)** improve error message when task files are not executable by @jdx in [#8705](#8705) - **(test)** update vfox provenance test for checksum-backed skip by @jdx in [#8703](#8703) - improve usage spec element support in tasks by @nkakouros in [#8623](#8623) - make env plugin (Module) vars available in Tera template context by @victor-founder in [#8682](#8682) - respect MISE_COLOR=0 for color_eyre error output by @jdx in [#8690](#8690) - add windows support for usage tool registry by @jdx in [#8713](#8713) ### 📚 Documentation - **(task)** clarify interactive task blocking behavior by @jdx in [#8685](#8685) - improve visibility of install_before setting by @jdx in [#8712](#8712) ### 📦 Registry - add rtk ([github:rtk-ai/rtk](https://github.com/rtk-ai/rtk)) by @bricelalu in [#8683](#8683) ### New Contributors - @victor-founder made their first contribution in [#8682](#8682) - @modestman made their first contribution in [#8666](#8666) - @bricelalu made their first contribution in [#8683](#8683)

Summary
mise-tasks/but lack the executable bit (common when created on Windows and cloned on macOS/Linux), show a clear error withchmod +xinstructions instead of the generic "no tasks defined" messagemise tasks lswhen no tasks found but non-executable files exist in task directoriesmise runandmise taskscasesCloses #8614
Test plan
mise run buildwith non-executable task files shows "non-executable" error withchmod +xsuggestionmise taskswith non-executable task files shows warning about non-executable fileschmod +x, bothmise tasksandmise runwork correctlytest_task_non_executable_errorpasses🤖 Generated with Claude Code
Note
Low Risk
Low risk: changes are limited to error/warning messaging when no tasks are detected (non-Windows) plus a new e2e test; core task execution logic is unchanged.
Overview
Improves the "no tasks" failure path by detecting non-executable files in task include directories and surfacing a clearer error suggesting
chmod +x(instead of the generic "no tasks defined" message).Adds a warning in
mise tasks lswhen no tasks exist at all but non-executable task files are present (to avoid false positives from flag filtering), and introduces an e2e test verifying both the warning/error and the success case after making files executable.Written by Cursor Bugbot for commit a363a40. This will update automatically on new commits. Configure here.