Repository navigation
fix(http): don't cap remote-fetch commands to 3s under prefer_offline - #11190
Conversation
PR #11066 caps remote-version lookups at 3s and disables retries whenever `prefer_offline()` is true, so shims and shell activation never stall. But `prefer_offline` is also a persistent user setting/env, and the cap was applied indiscriminately — including to commands whose entire purpose is to fetch remote versions/tags. As a result, with `prefer_offline` enabled, `mise lock` builds lockfiles against a single 3s no-retry attempt and silently ignores a configured `fetch_remote_versions_timeout` of 20s/30s, timing out on slow registry responses (e.g. api.github.com). Reported in discussion #11185. Introduce `REMOTE_FETCH_COMMAND` (lock, ls-remote, outdated, upgrade) and a `Settings::bound_remote_version_lookups()` predicate. These commands opt out of the fast-path cap and honor the full configured timeout and retry budget even under `prefer_offline`; shims, activation, and `mise x` are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
📝 WalkthroughWalkthroughRemote-fetch command detection distinguishes version-enumeration commands from other offline operations. Timeout caps and retry reductions now apply only to bounded remote lookups, while fetch commands retain configured budgets under ChangesRemote fetch timeout handling
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant CLI
participant REMOTE_FLAG as "env::REMOTE_FETCH_COMMAND"
participant Settings
participant Client
CLI->>REMOTE_FLAG: inspect argv
REMOTE_FLAG-->>Settings: expose command classification
Settings->>Settings: evaluate bound_remote_version_lookups()
Client->>Settings: request timeout and retry settings
Settings-->>Client: return capped or configured values
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR preserves the full HTTP budget for commands that explicitly enumerate remote versions. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (3): Last reviewed commit: "fix(http): classify commands after globa..." | Re-trigger Greptile |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/env.rs`:
- Around line 754-761: Update remote_fetch_command to parse value-bearing global
options before identifying the subcommand, using the existing CLI parser or
explicitly consuming values for options such as --cd and --profile. Ensure
commands like “mise --cd /tmp lock” select lock rather than the option value,
preserving correct prefer_offline behavior, and add coverage for these options.
In `@src/http.rs`:
- Around line 1798-1816: The test
test_remote_fetch_command_keeps_full_budget_under_prefer_offline manually
restores the process-global REMOTE_FETCH_COMMAND flag, so panics can leave it
enabled. Replace the prev/store cleanup with a local RAII guard whose Drop
implementation restores the original value, ensuring restoration occurs during
unwinding.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Central YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: 690e22c5-1712-44ea-80ba-3d86ad48bbac
📒 Files selected for processing (3)
src/config/settings.rssrc/env.rssrc/http.rs
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.7.11 x -- echo |
23.1 ± 1.6 | 19.5 | 28.7 | 1.00 |
mise x -- echo |
26.1 ± 2.6 | 22.1 | 47.9 | 1.13 ± 0.13 |
x -- echo measured 13% slower, but hyperfine reported statistical outliers. |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.7.11 env |
22.6 ± 1.9 | 17.9 | 29.9 | 1.00 |
mise env |
25.4 ± 2.2 | 20.9 | 35.3 | 1.13 ± 0.14 |
env measured 13% slower, but the relative uncertainty overlaps the 10% threshold. |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.7.11 hook-env |
23.5 ± 1.8 | 19.4 | 30.0 | 1.00 |
mise hook-env |
26.5 ± 2.1 | 21.3 | 35.0 | 1.13 ± 0.13 |
hook-env measured 13% slower, but the relative uncertainty overlaps the 10% threshold. |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.7.11 ls |
19.3 ± 1.6 | 15.9 | 27.4 | 1.00 |
mise ls |
21.9 ± 1.5 | 18.3 | 28.9 | 1.13 ± 0.12 |
ls measured 13% slower, but the relative uncertainty overlaps the 10% threshold. |
xtasks/test/perf
| Command | mise-2026.7.11 | mise | Variance |
|---|---|---|---|
| install (cached) | 179ms | 193ms | -7% |
| ls (cached) | 71ms | 76ms | -6% |
| bin-paths (cached) | 76ms | 79ms | -3% |
| task-ls (cached) | 160ms | 159ms | +0% |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/cli/mod.rs (1)
422-457: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winHandle attached short values on the short-flag path Attached forms like
-C/tmp,-C=/tmp, or-j8should advance by one argv slot, not two; otherwise the next positional/subcommand is skipped andremote_fetch_commandcan miss a real fetch command.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cli/mod.rs` around lines 422 - 457, Update first_non_global_arg_idx’s short-flag handling so attached values such as -C/tmp, -C=/tmp, and -j8 are treated as consumed within the current argument and never cause i to advance by two. Only increment past the following argv entry when a short flag requires a separate value; preserve existing behavior for standalone flags and long options.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/cli/mod.rs`:
- Around line 422-457: Update first_non_global_arg_idx’s short-flag handling so
attached values such as -C/tmp, -C=/tmp, and -j8 are treated as consumed within
the current argument and never cause i to advance by two. Only increment past
the following argv entry when a short flag requires a separate value; preserve
existing behavior for standalone flags and long options.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Central YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: bf36fd2d-747f-43fd-978f-f1a02d156d03
📒 Files selected for processing (3)
src/cli/mod.rssrc/env.rssrc/http.rs
🚧 Files skipped from review as they are similar to previous changes (2)
- src/env.rs
- src/http.rs
Summary
prefer_offlinefast-path budget (a single ~3s attempt, no retries) to commands whose whole job is to enumerate remote versions/tags.env::REMOTE_FETCH_COMMAND(lock,ls-remote,outdated,upgrade) andSettings::bound_remote_version_lookups().fetch_remote_versions_timeoutand retry budget even whenprefer_offlineis set. Shims, shell activation, andmise xare unchanged.Fixes #11185.
Root cause
#11066 ("fail fast when network is unavailable") caps remote-version lookups at 3s and disables HTTP retries whenever
Settings::prefer_offline()is true, so latency-sensitive fast commands (shims, activation,mise x) make at most one bounded attempt.But
prefer_offlineis also a persistent user setting /MISE_PREFER_OFFLINEenv var, and the cap was gated onprefer_offline()alone — with no distinction for the command being run. So withprefer_offlineenabled,mise lock(whose entire purpose is to fetch remote tags/releases to build a lockfile) is forced into a single 3s no-retry attempt.The
3.00sin the error is only reachable through this cap —Duration::from_secs(3)is the sole 3s constant in the HTTP stack, and both cap sites plusrequest_timeout()are gated onprefer_offline(). Before #11066 the cap didn't exist, which is why reverting to v2026.7.7 works.User impact
With
prefer_offlineset:Raising
fetch_remote_versions_timeoutto 20s/30s has no effect — the cap silently overrides it, even though the hint tells the user to change that exact setting. After this change,mise lock/ls-remote/outdated/upgradeuse the configured timeout and retries again. Fast/interactive commands keep the bounded fast-path behavior from #11066.Testing
cargo test --bin mise -- offline— 14 passedcargo test --bin mise -- http::tests— 52 passedtest_remote_fetch_command_keeps_full_budget_under_prefer_offlineThis pull request was generated by Claude.
Note
Medium Risk
Changes early argv parsing and HTTP timeout/retry gating for prefer_offline paths; impact is scoped with new tests but affects network behavior for common CLI invocations.
Overview
With
prefer_offlineenabled, remote version lookups were always forced through the fast-path budget (~3s timeout, no retries), so commands likemise lock,ls-remote,outdated, andupgradecould time out even when users raisedfetch_remote_versions_timeout.This change introduces
REMOTE_FETCH_COMMANDandSettings::bound_remote_version_lookups()so only true fast-path usage keeps the cap; remote-enumeration commands get the full configured timeout and retry budget. HTTP fetch clients and settings now gate onbound_remote_version_lookups()instead ofprefer_offline()alone.prefer_offline/ command classification no longer treats global option values as the subcommand: detection goes through sharedfirst_non_global_arg_idx, including a fix for attached short flags (-C/tmp,-j8). Regression tests cover both behaviors.Reviewed by Cursor Bugbot for commit 67112c1. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit