Skip to content

fix(http): don't cap remote-fetch commands to 3s under prefer_offline - #11190

Merged
jdx merged 3 commits into
mainfrom
fix/lock-prefer-offline-timeout
Jul 22, 2026
Merged

jdx merged 3 commits into
mainfrom
fix/lock-prefer-offline-timeout

Conversation

@jdx

@jdx jdx commented Jul 22, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Stop applying the prefer_offline fast-path budget (a single ~3s attempt, no retries) to commands whose whole job is to enumerate remote versions/tags.
  • Add env::REMOTE_FETCH_COMMAND (lock, ls-remote, outdated, upgrade) and Settings::bound_remote_version_lookups().
  • These commands now honor the full configured fetch_remote_versions_timeout and retry budget even when prefer_offline is set. Shims, shell activation, and mise x are 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_offline is also a persistent user setting / MISE_PREFER_OFFLINE env var, and the cap was gated on prefer_offline() alone — with no distinction for the command being run. So with prefer_offline enabled, 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.00s in 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 plus request_timeout() are gated on prefer_offline(). Before #11066 the cap didn't exist, which is why reverting to v2026.7.7 works.

User impact

With prefer_offline set:

mise WARN  [openai/codex] failed to fetch version tags for lockfile, URL may be incorrect:
HTTP timed out after 3.00s for https://api.github.com/repos/openai/codex/releases?per_page=100
(change with `fetch_remote_versions_timeout` or env `MISE_FETCH_REMOTE_VERSIONS_TIMEOUT`).

Raising fetch_remote_versions_timeout to 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 / upgrade use the configured timeout and retries again. Fast/interactive commands keep the bounded fast-path behavior from #11066.

Testing

  • cargo test --bin mise -- offline — 14 passed
  • cargo test --bin mise -- http::tests — 52 passed
  • New regression test test_remote_fetch_command_keeps_full_budget_under_prefer_offline

This 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_offline enabled, remote version lookups were always forced through the fast-path budget (~3s timeout, no retries), so commands like mise lock, ls-remote, outdated, and upgrade could time out even when users raised fetch_remote_versions_timeout.

This change introduces REMOTE_FETCH_COMMAND and Settings::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 on bound_remote_version_lookups() instead of prefer_offline() alone.

prefer_offline / command classification no longer treats global option values as the subcommand: detection goes through shared first_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

  • Bug Fixes
    • Improved remote version and tag lookup behavior for commands that explicitly fetch remote data.
    • Prevented overly aggressive timeouts and retry limits during remote enumeration when offline preference is enabled.
    • Enhanced detection of remote-enumeration commands when preceded by global options, ensuring these operations keep the full configured timeout budget and retry settings.

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>
@coderabbitai

coderabbitai Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Remote-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 prefer_offline.

Changes

Remote fetch timeout handling

Layer / File(s) Summary
Remote-fetch command detection
src/cli/mod.rs, src/env.rs
Improves global-argument parsing and adds REMOTE_FETCH_COMMAND detection for supported remote-version and tag enumeration commands, including global-option cases.
Bounded lookup settings and HTTP behavior
src/config/settings.rs, src/http.rs
Adds bound_remote_version_lookups() and uses it for remote-version timeout caps, HTTP retries, and fetch request timeouts. Tests verify full configured budgets for remote-fetch commands.

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
Loading

Suggested reviewers: jambalaya56562, risu729

Poem

I hop through flags beneath the moon,
Mark remote fetches by their tune.
Full budgets bloom where tags are sought,
While bounded paths stay quick as thought.
The timeout carrots now align! 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 61.90% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: removing the 3s cap for remote-fetch commands when prefer_offline is set.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR preserves the full HTTP budget for commands that explicitly enumerate remote versions. The main changes are:

  • Adds command-aware handling for lock, ls-remote, outdated, upgrade, and their aliases.
  • Keeps the three-second, no-retry path for latency-sensitive commands.
  • Uses global-option-aware parsing for both command classes.
  • Adds tests for separate and attached global option values.

Confidence Score: 5/5

This looks safe to merge.

  • Both previously affected command classes now use the global-option-aware parser.
  • Tests cover separate values and attached short-option values.
  • No blocking issue remains in the updated code.

Important Files Changed

Filename Overview
src/cli/mod.rs Exposes the command-index helper and handles separate and attached short-option values correctly.
src/env.rs Classifies remote-fetch and latency-sensitive commands through the same global-option-aware parser.
src/config/settings.rs Centralizes when remote version lookups receive the bounded timeout and retry budget.
src/http.rs Uses the centralized budget decision and tests the full-budget remote-fetch path.

Reviews (3): Last reviewed commit: "fix(http): classify commands after globa..." | Re-trigger Greptile

Comment thread src/env.rs Resolved

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4aa08f4 and 4e53eb2.

📒 Files selected for processing (3)
  • src/config/settings.rs
  • src/env.rs
  • src/http.rs

Comment thread src/env.rs Resolved
Comment thread src/http.rs Resolved
@github-actions

github-actions Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

Hyperfine Performance

mise x -- echo

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
⚠️ Inconclusive: 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
⚠️ Inconclusive: 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
⚠️ Inconclusive: 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
⚠️ Inconclusive: 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%

Comment thread src/env.rs Resolved

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Handle attached short values on the short-flag path Attached forms like -C/tmp, -C=/tmp, or -j8 should advance by one argv slot, not two; otherwise the next positional/subcommand is skipped and remote_fetch_command can 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

📥 Commits

Reviewing files that changed from the base of the PR and between 4e53eb2 and 9c39f60.

📒 Files selected for processing (3)
  • src/cli/mod.rs
  • src/env.rs
  • src/http.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/env.rs
  • src/http.rs

@jdx
jdx enabled auto-merge (squash) July 22, 2026 15:30
@jdx
jdx merged commit 699e4c4 into main Jul 22, 2026
34 checks passed
@jdx
jdx deleted the fix/lock-prefer-offline-timeout branch July 22, 2026 15:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant