feat(cli): handle non-existent working directories gracefully#6304
Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR adds graceful error handling when mise is run from a non-existent working directory, preventing panics and providing friendly error messages. Previously, mise would panic if the current directory was deleted while a shell session was active in it.
- Added early directory existence check in main.rs with selective command allowlist
- Fixed config_root.rs to handle
absolutize()failures gracefully - Added comprehensive e2e test coverage for various scenarios
Reviewed Changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/main.rs | Added current directory validation with allowlist for commands that don't require cwd |
| src/config/config_file/config_root.rs | Changed unwrap_or to unwrap_or_else to handle absolutize failures |
| e2e/cli/test_nonexistent_cwd | Added comprehensive test script for non-existent directory scenarios |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
src/main.rs
Outdated
| let cwd_not_required = args.iter().any(|arg| { | ||
| arg == "--version" || arg == "-V" || | ||
| arg == "--help" || arg == "-h" || | ||
| arg == "ls" || arg == "list" || // ls can show global tools | ||
| arg == "doctor" || arg == "dr" || // doctor can run without cwd | ||
| arg == "plugins" || arg == "p" || // plugins list doesn't need cwd | ||
| arg == "version" || arg == "v" // version info doesn't need cwd | ||
| }); |
There was a problem hiding this comment.
The hardcoded command list creates maintenance burden. Consider extracting this into a constant array or method to improve maintainability and make it easier to add new commands that don't require cwd.
src/main.rs
Outdated
| arg == "ls" || arg == "list" || // ls can show global tools | ||
| arg == "doctor" || arg == "dr" || // doctor can run without cwd | ||
| arg == "plugins" || arg == "p" || // plugins list doesn't need cwd | ||
| arg == "version" || arg == "v" // version info doesn't need cwd |
There was a problem hiding this comment.
This line duplicates the version check from line 130. The --version/-V flags and version/v subcommands should be consolidated to avoid redundancy.
Previously, mise would panic when run from a directory that no longer exists (e.g., after the directory was deleted while the shell was still in it). This change adds proper error handling to provide a friendly error message instead of panicking. Changes: - Add early check for current directory existence in main.rs - Provide clear error message showing the problematic directory path - Allow certain commands (--version, ls, doctor, etc.) to work without cwd - Fix panic in config_root.rs when absolutize() fails - Add comprehensive e2e test for non-existent directory scenarios Fixes the panic that occurred when running mise commands from deleted directories. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
a04c54a to
51369b9
Compare
Move the working directory check logic into a dedicated helper function check_working_directory() for better code organization and maintainability.
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.9.10 x -- echo |
19.4 ± 0.5 | 18.7 | 24.6 | 1.00 |
mise x -- echo |
19.6 ± 0.6 | 18.8 | 21.8 | 1.01 ± 0.04 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.9.10 env |
19.0 ± 0.9 | 18.3 | 32.9 | 1.00 |
mise env |
19.1 ± 0.6 | 18.3 | 22.9 | 1.01 ± 0.06 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.9.10 hook-env |
18.7 ± 0.6 | 17.9 | 20.3 | 1.01 ± 0.04 |
mise hook-env |
18.5 ± 0.5 | 17.9 | 21.0 | 1.00 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.9.10 ls |
16.9 ± 0.7 | 15.8 | 18.8 | 1.03 ± 0.05 |
mise ls |
16.4 ± 0.5 | 15.8 | 18.9 | 1.00 |
xtasks/test/perf
| Command | mise-2025.9.10 | mise | Variance |
|---|---|---|---|
| install (cached) | 168ms | ✅ 104ms | +61% |
| ls (cached) | 63ms | 63ms | +0% |
| bin-paths (cached) | 70ms | 70ms | +0% |
| task-ls (cached) | 487ms | 482ms | +1% |
✅ Performance improvement: install cached is 61%
## [2025.9.12](https://github.com/jdx/mise/compare/v2025.9.11..v2025.9.12) - 2025-09-16 ### 🐛 Bug Fixes - **(ci)** properly exclude aqua-registry files from hk linting by @jdx in [42d7758](jdx/mise@42d7758) ### Chore - **(release)** embed aqua-registry under crate and publish like vfox by @jdx in [#6306](jdx/mise#6306) - ignore aqua-registry assets from prettier by @jdx in [047d77b](jdx/mise@047d77b) - disable "useless cat" shellcheck by @jdx in [a6def59](jdx/mise@a6def59) ## [2025.9.11](https://github.com/jdx/mise/compare/v2025.9.10..v2025.9.11) - 2025-09-16 ### 📦 Registry - indicate aws-cli is v2 by @jayvdb in [#6300](jdx/mise#6300) ### 🚀 Features - **(ci)** run all registry tools when workflow_dispatch is triggered by @jdx in [#6295](jdx/mise#6295) - **(cli)** handle non-existent working directories gracefully by @jdx in [#6304](jdx/mise#6304) - **(set)** add -E/--env flag to mise set command by @jdx in [#6291](jdx/mise#6291) - **(tasks)** make auto outputs default by @risu729 in [#6137](jdx/mise#6137) ### 🐛 Bug Fixes - align crate versions to fix release-plz script by @jdx in [5a464e9](jdx/mise@5a464e9) ### 🚜 Refactor - **(aqua)** extract aqua registry into internal subcrate by @jdx in [#6293](jdx/mise#6293) ### 📚 Documentation - fix mkdir paths by @risu729 in [#6298](jdx/mise#6298) - fix rust profile default by @risu729 in [#6305](jdx/mise#6305) ### Chore - **(aqua-registry)** remove unused aqua-registry files by @jdx in [#6294](jdx/mise#6294) - **(release)** make release-plz idempotent for existing crate versions by @jdx in [dbdfd6a](jdx/mise@dbdfd6a) - **(release)** skip publishing mise when aqua-registry is a path dep by @jdx in [47efffd](jdx/mise@47efffd) - keep aqua-registry LICENSE file by @risu729 in [#6297](jdx/mise#6297) ### New Contributors - @jayvdb made their first contribution in [#6300](jdx/mise#6300) ## [2025.9.10](https://github.com/jdx/mise/compare/v2025.9.9..v2025.9.10) - 2025-09-13 ### 📦 Registry - use asdf to install semver-tool by @jylenhof in [#6233](jdx/mise#6233) ### 🐛 Bug Fixes - **(tool-stub)** detect binary names from single-file downloads by @jdx in [#6281](jdx/mise#6281) ### 🚜 Refactor - allow any collection types in deserialize_arr by @risu729 in [#6282](jdx/mise#6282) - use deserialize_arr for task runs by @risu729 in [#6253](jdx/mise#6253) ### 📚 Documentation - **(getting-started)** add backends step with diagram, github example, env vars and simple tasks by @jdx in [#6288](jdx/mise#6288) - simplify OS detection in tool plugin development by @jdx in [#6287](jdx/mise#6287) - update backend plugin template references by @jdx in [942f5eb](jdx/mise@942f5eb) ### 📦️ Dependency Updates - update rust crate chrono to v0.4.42 by @renovate[bot] in [#6274](jdx/mise#6274) - update taiki-e/install-action digest to 0154864 by @renovate[bot] in [#6273](jdx/mise#6273) ### Chore - **(schema)** fix schema for subtasks by @risu729 in [#6289](jdx/mise#6289) - update render:schema task by @risu729 in [#6275](jdx/mise#6275) ## [2025.9.9](https://github.com/jdx/mise/compare/v2025.9.8..v2025.9.9) - 2025-09-11 ### 🐛 Bug Fixes - **(backend)** make HTTP installs atomic and serialize with cache lock by @jdx in [#6259](jdx/mise#6259) - **(env)** allow nested env._.path directives by @risu729 in [#6160](jdx/mise#6160) - **(env)** disallow nested env objects by @risu729 in [#6268](jdx/mise#6268) - **(schema)** allow nested arrays in task.depends by @risu729 in [#6265](jdx/mise#6265) - **(task)** resolve jobs=1 hang and keep-order panic; improve Ctrl-C handling by @jdx in [#6264](jdx/mise#6264) - **(tasks)** stop CLI group after first failure without --continue-on-error by @jdx in [#6270](jdx/mise#6270) ### 📚 Documentation - fixed toml issues in URL replacements settings documentation by @ThomasSteinbach in [#6269](jdx/mise#6269) ### Chore - **(schema)** strict oneOf branches and DRY env_directive in schemas by @jdx in [#6271](jdx/mise#6271) - add schema linter by @risu729 in [#6267](jdx/mise#6267) ## [2025.9.8](https://github.com/jdx/mise/compare/v2025.9.7..v2025.9.8) - 2025-09-10 ### 🐛 Bug Fixes - **(tasks)** prevent hang when task fails in sequence by @jdx in [#6260](jdx/mise#6260) - **(version)** fetch mise version if cached version is older than the current by @risu729 in [#6252](jdx/mise#6252) ### 📦️ Dependency Updates - update rhysd/action-setup-vim action to v1.4.3 by @renovate[bot] in [#6249](jdx/mise#6249) ## [2025.9.7](https://github.com/jdx/mise/compare/v2025.9.6..v2025.9.7) - 2025-09-09 ### 🐛 Bug Fixes - **(env)** allow mixed map for env._.file by @risu729 in [#6148](jdx/mise#6148) - **(tasks)** restore parallel starts with poetry via list_paths cache and stable exec-env cache by @jdx in [#6237](jdx/mise#6237) - add 'unknown' to the list of OS patterns by @efussi in [#6235](jdx/mise#6235) - propagate errors from backend installs by @jdx in [#6236](jdx/mise#6236) ### 📦️ Dependency Updates - update taiki-e/install-action digest to 0c5db7f by @renovate[bot] in [#6244](jdx/mise#6244) - update golang docker tag to v1.25.1 by @renovate[bot] in [#6247](jdx/mise#6247) - update dependency vitepress to v1.6.4 by @renovate[bot] in [#6246](jdx/mise#6246) ### New Contributors - @efussi made their first contribution in [#6235](jdx/mise#6235)
Summary
Background
Previously, mise would panic when run from a directory that no longer exists (e.g., after the directory was deleted while the shell was still in it). This could happen when:
Changes
absolutize()failures gracefullyApproach
Instead of blocking certain commands or maintaining an allowlist, mise now:
Test Plan
test_nonexistent_cwdthat tests multiple mise commandsExample Warning
Platform Support
🤖 Generated with Claude Code