Skip to content

Fix reachable panic in CLI flag handling#14299

Closed
gesslerpd wants to merge 1 commit intoastral-sh:mainfrom
gesslerpd:feature/flag-panic
Closed

Fix reachable panic in CLI flag handling#14299
gesslerpd wants to merge 1 commit intoastral-sh:mainfrom
gesslerpd:feature/flag-panic

Conversation

@gesslerpd
Copy link

@gesslerpd gesslerpd commented Jun 26, 2025

Summary

Previously it was possible to reach panic condition in CLI flag handling when opposing flags were passed at different subcommand levels.

For example uv self --offline version --no-offline panics with the following RUST_BACKTRACE.

thread 'main2' panicked at crates\uv-cli\src\options.rs:17:17:
internal error: entered unreachable code: Clap should make this impossible
stack backtrace:
   0:     0x7ff6ee2a2ffc - <unknown>
   1:     0x7ff6ede968da - <unknown>
   2:     0x7ff6ee2a2557 - <unknown>
   3:     0x7ff6ee2a2e54 - <unknown>
   4:     0x7ff6ee2a2195 - <unknown>
   5:     0x7ff6ee2c96d2 - <unknown>
   6:     0x7ff6ee2c965f - <unknown>
   7:     0x7ff6ee2ccd4e - <unknown>
   8:     0x7ff6f031b941 - <unknown>
   9:     0x7ff6ee4e434a - <unknown>
  10:     0x7ff6ee674184 - <unknown>
  11:     0x7ff6ee65ebde - <unknown>
  12:     0x7ff6ef495290 - <unknown>
  13:     0x7ff6edcc6622 - <unknown>
  14:     0x7ff6ee2c40bd - <unknown>
  15:     0x7ff852477374 - BaseThreadInitThunk
  16:     0x7ff8527dcc91 - RtlUserThreadStart

thread 'main' panicked at C:\a\uv\uv\crates\uv\src\lib.rs:2275:10:
Tokio executor failed, was there a panic?: Any { .. }
stack backtrace:
   0:     0x7ff6ee2a2ffc - <unknown>
   1:     0x7ff6ede968da - <unknown>
   2:     0x7ff6ee2a2557 - <unknown>
   3:     0x7ff6ee2a2e54 - <unknown>
   4:     0x7ff6ee2a2195 - <unknown>
   5:     0x7ff6ee2c9709 - <unknown>
   6:     0x7ff6ee2c965f - <unknown>
   7:     0x7ff6ee2ccd4e - <unknown>
   8:     0x7ff6f031b941 - <unknown>
   9:     0x7ff6f031bd10 - <unknown>
  10:     0x7ff6edda51a2 - <unknown>
  11:     0x7ff6ef494186 - <unknown>
  12:     0x7ff6edda5f92 - <unknown>
  13:     0x7ff6f02f544c - <unknown>
  14:     0x7ff852477374 - BaseThreadInitThunk
  15:     0x7ff8527dcc91 - RtlUserThreadStart

Test Plan

The panic condition is removed in favor of None so should be impossible to reach condition now.

Based on the unreachable message, not sure if this is some issue with Clap or uv's usage of it but seems reasonable they would cancel out to None.

@zanieb
Copy link
Member

zanieb commented Jun 26, 2025

Hm, but this should be unreachable since these use overrides_with?

uv/crates/uv-cli/src/lib.rs

Lines 239 to 244 in 5b2c359

/// When disabled, uv will only use locally cached data and locally available files.
#[arg(global = true, long, overrides_with("no_offline"), env = EnvVars::UV_OFFLINE, value_parser = clap::builder::BoolishValueParser::new())]
pub offline: bool,
#[arg(global = true, long, overrides_with("offline"), hide = true)]
pub no_offline: bool,

@zanieb
Copy link
Member

zanieb commented Jun 26, 2025

I guess this is a Clap bug?

@gesslerpd
Copy link
Author

gesslerpd commented Jun 26, 2025

Yeah it could be a Clap issue, seems reasonable for UV to make them cancel out for now. Purposely used a non-destructive example to show it but think it has to do with when opposing flags exist at different subcommand levels.

@zanieb
Copy link
Member

zanieb commented Jun 26, 2025

Yeah that makes sense. I don't think they should cancel out though, the latter one should "win". If they cancel out, we'll use the default value instead so I think this is a correctness bug if we don't panic.

@gesslerpd
Copy link
Author

gesslerpd commented Jun 26, 2025

I'm not familiar with Clap, since these options are shared across levels I think that following should be equivalent (using harmless repro command)

  • uv --offline --no-offline self version
  • uv --offline self version --no-offline

Possibly the top example is not currently a cancel out scenario though, when clap is doing its normal overrides_with behavior?

It's a whatever is last wins?

In that case, I guess then only way to workaround this would be fixing in Clap.

@gesslerpd
Copy link
Author

Closing in favor of issue/pr in https://github.com/clap-rs/clap

@konstin
Copy link
Member

konstin commented Jun 27, 2025

Filed upstream: clap-rs/clap#6049

konstin added a commit that referenced this pull request Jun 30, 2025
Clap does not perform global validation, so flag that are declared as overriding can be set at the same time: clap-rs/clap#6049. This would previously cause a panic. We work around this by choosing the yes-value always and writing a warning.

An alternative would be erroring when both are set, but it's unclear to me if this may break things we want to support. (`UV_OFFLINE=1 cargo run -q pip --no-offline install tqdm --no-cache` is already banned).

Fixes #14299

**Test Plan**

```
$ cargo run -q pip --offline install --no-offline tqdm --no-cache
  warning: Boolean flags on different levels are not correctly supported (clap-rs/clap#6049)
    × No solution found when resolving dependencies:
    ╰─▶ Because tqdm was not found in the cache and you require tqdm, we can conclude that your requirements are unsatisfiable.

        hint: Packages were unavailable because the network was disabled. When the network is disabled, registry packages may only be read from the cache.
```
konstin added a commit that referenced this pull request Jun 30, 2025
Clap does not perform global validation, so flag that are declared as overriding can be set at the same time: clap-rs/clap#6049. This would previously cause a panic. We work around this by choosing the yes-value always and writing a warning.

An alternative would be erroring when both are set, but it's unclear to me if this may break things we want to support. (`UV_OFFLINE=1 cargo run -q pip --no-offline install tqdm --no-cache` is already banned).

Fixes #14299

**Test Plan**

```
$ cargo run -q pip --offline install --no-offline tqdm --no-cache
  warning: Boolean flags on different levels are not correctly supported (clap-rs/clap#6049)
    × No solution found when resolving dependencies:
    ╰─▶ Because tqdm was not found in the cache and you require tqdm, we can conclude that your requirements are unsatisfiable.

        hint: Packages were unavailable because the network was disabled. When the network is disabled, registry packages may only be read from the cache.
```
zanieb pushed a commit that referenced this pull request Jul 1, 2025
Clap does not perform global validation, so flag that are declared as
overriding can be set at the same time:
clap-rs/clap#6049. This would previously cause
a panic. We work around this by choosing the yes-value always and
writing a warning.

An alternative would be erroring when both are set, but it's unclear to
me if this may break things we want to support. (`UV_OFFLINE=1 cargo run
-q pip --no-offline install tqdm --no-cache` is already banned).

Fixes #14299

**Test Plan**

```
$ cargo run -q pip --offline install --no-offline tqdm --no-cache
  warning: Boolean flags on different levels are not correctly supported (clap-rs/clap#6049)
    × No solution found when resolving dependencies:
    ╰─▶ Because tqdm was not found in the cache and you require tqdm, we can conclude that your requirements are unsatisfiable.

        hint: Packages were unavailable because the network was disabled. When the network is disabled, registry packages may only be read from the cache.
```
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.

3 participants