Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

value_parser that should return Vec<u8> panics with Mismatch between definition and access of Payload. Could not downcast to u8, need to downcast to alloc::vec::Vec<u8> #4481

Closed
2 tasks done
vslynko opened this issue Nov 14, 2022 · 5 comments
Labels
A-derive Area: #[derive]` macro API C-bug Category: Updating dependencies

Comments

@vslynko
Copy link

vslynko commented Nov 14, 2022

Please complete the following tasks

Rust Version

rustc 1.64.0 (a55dd71d5 2022-09-19)

Clap Version

clap = { version = "4.0.23", features = ["derive"] }

Minimal reproducible code

use clap::Parser;

fn parse_hex_values(s: &str) -> Result<Vec<u8>, hex::FromHexError> {
    hex::decode(s.trim_start_matches("0x"))
}

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
pub struct Cli {
    #[arg(name = "Payload", value_parser(parse_hex_values))]
    payload: Vec<u8>,
}

fn main() {
    println!("Hello, world!");
    let _args = Cli::parse();
}

Steps to reproduce the bug with the above code

cargo run -- 0x11

cargo.Toml should also contain hex = "0.4.3" dependency

Actual Behaviour

Main thread panics with
thread 'main' panicked at 'Mismatch between definition and access of Payload. Could not downcast to u8, need to downcast to alloc::vec::Vec<u8>

~\source\clap_bug on master  ● λ cargo run -- 0x11
   Compiling adler v1.0.2
   Compiling gimli v0.26.2
   Compiling cfg-if v1.0.0
   Compiling rustc-demangle v0.1.21
   Compiling memchr v2.5.0
   Compiling libc v0.2.137
   Compiling miniz_oxide v0.5.4
   Compiling object v0.29.0                                                                                   
   Compiling addr2line v0.17.0
   Compiling backtrace v0.3.66
   Compiling clap v4.0.24
   Compiling clap_bug v0.1.0 (C:\Users\vadim\source\clap_bug)
    Finished dev [unoptimized + debuginfo] target(s) in 5.74s
     Running `target\debug\clap_bug.exe 0x11`
Hello, world!
[      clap::builder::command]  Command::_do_parse
[      clap::builder::command]  Command::_build: name="clap_bug"
[      clap::builder::command]  Command::_propagate:clap_bug
[      clap::builder::command]  Command::_check_help_and_version:clap_bug expand_help_tree=false
[      clap::builder::command]  Command::long_help_exists
[      clap::builder::command]  Command::_check_help_and_version: Building default --help
[      clap::builder::command]  Command::_check_help_and_version: Building default --version
[      clap::builder::command]  Command::_propagate_global_args:clap_bug
[clap::builder::debug_asserts]  Command::_debug_asserts
[clap::builder::debug_asserts]  Arg::_debug_asserts:Payload
[clap::builder::debug_asserts]  Arg::_debug_asserts:help
[clap::builder::debug_asserts]  Arg::_debug_asserts:version
[clap::builder::debug_asserts]  Command::_verify_positionals
[        clap::parser::parser]  Parser::get_matches_with
[        clap::parser::parser]  Parser::get_matches_with: Begin parsing 'RawOsStr("0x11")' ([48, 120, 49, 49])
[        clap::parser::parser]  Parser::possible_subcommand: arg=Ok("0x11")
[        clap::parser::parser]  Parser::get_matches_with: sc=None
[        clap::parser::parser]  Parser::get_matches_with: Positional counter...1
[        clap::parser::parser]  Parser::get_matches_with: Low index multiples...false
[        clap::parser::parser]  Parser::resolve_pending: id="Payload"
[        clap::parser::parser]  Parser::react action=Append, identifier=Some(Index), source=CommandLine       
[        clap::parser::parser]  Parser::remove_overrides: id="Payload"
[   clap::parser::arg_matcher]  ArgMatcher::start_custom_arg: id="Payload", source=CommandLine
[      clap::builder::command]  Command::groups_for_arg: id="Payload"
[   clap::parser::arg_matcher]  ArgMatcher::start_custom_arg: id="Cli", source=CommandLine
[        clap::parser::parser]  Parser::push_arg_values: ["0x11"]
[        clap::parser::parser]  Parser::add_single_val_to_arg: cur_idx:=1
[   clap::parser::arg_matcher]  ArgMatcher::needs_more_vals: o=Payload, pending=0
[   clap::parser::arg_matcher]  ArgMatcher::needs_more_vals: expected=1..=18446744073709551615, actual=0      
[        clap::parser::parser]  Parser::react not enough values passed in, leaving it to the validator to complain
[        clap::parser::parser]  Parser::add_defaults
[        clap::parser::parser]  Parser::add_defaults:iter:Payload:
[        clap::parser::parser]  Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser]  Parser::add_default_value:iter:Payload: doesn't have default vals
[        clap::parser::parser]  Parser::add_defaults:iter:help:
[        clap::parser::parser]  Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser]  Parser::add_default_value:iter:help: doesn't have default vals
[        clap::parser::parser]  Parser::add_defaults:iter:version:
[        clap::parser::parser]  Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser]  Parser::add_default_value:iter:version: doesn't have default vals
[     clap::parser::validator]  Validator::validate
[     clap::parser::validator]  Validator::validate_conflicts
[     clap::parser::validator]  Validator::validate_exclusive
[     clap::parser::validator]  Validator::validate_conflicts::iter: id="Payload"
[     clap::parser::validator]  Conflicts::gather_conflicts: arg="Payload"
[      clap::builder::command]  Command::groups_for_arg: id="Payload"
[     clap::parser::validator]  Conflicts::gather_direct_conflicts id="Payload", conflicts=[]
[     clap::parser::validator]  Conflicts::gather_direct_conflicts id="Cli", conflicts=[]
[     clap::parser::validator]  Conflicts::gather_conflicts: conflicts=[]
[     clap::parser::validator]  Validator::validate_required: required=ChildGraph([])
[     clap::parser::validator]  Validator::gather_requires
[     clap::parser::validator]  Validator::gather_requires:iter:"Payload"
[     clap::parser::validator]  Validator::gather_requires:iter:"Cli"
[     clap::parser::validator]  Validator::gather_requires:iter:"Cli":group
[     clap::parser::validator]  Validator::validate_required: is_exclusive_present=false
[   clap::parser::arg_matcher]  ArgMatcher::get_global_values: global_arg_vec=[]
thread 'main' panicked at 'Mismatch between definition and access of `Payload`. Could not downcast to u8, need to downcast to alloc::vec::Vec<u8>
', src\main.rs:11:14
stack backtrace:
   0: std::panicking::begin_panic_handler
             at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library\std\src\panicking.rs:584
   1: core::panicking::panic_fmt
             at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library\core\src\panicking.rs:142
   2: enum$<clap::parser::error::MatchesError, 1, 18446744073709551615, Downcast>::unwrap<enum$<core::option::Option<clap::parser::matches::arg_matches::Values<u8> >, 1, 18446744073709551615, Some> >
             at C:\Users\vadim\.cargo\registry\src\gh.neting.cc-1ecc6299db9ec823\clap-4.0.24\src\parser\error.rs:30
   3: clap::parser::matches::arg_matches::ArgMatches::remove_many<u8>
             at C:\Users\vadim\.cargo\registry\src\gh.neting.cc-1ecc6299db9ec823\clap-4.0.24\src\parser\matches\arg_matches.rs:338
   4: clap_bug::impl$2::from_arg_matches_mut
             at .\src\main.rs:7
   5: clap::derive::Parser::parse<clap_bug::Cli>
             at C:\Users\vadim\.cargo\registry\src\gh.neting.cc-1ecc6299db9ec823\clap-4.0.24\src\derive.rs:83   
   6: clap_bug::main
             at .\src\main.rs:16
   7: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
             at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52\library\core\src\ops\function.rs:248
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
error: process didn't exit successfully: `target\debug\clap_bug.exe 0x11` (exit code: 101)

Expected Behaviour

The result of parse_hex_values should be assigned to payload field.

Additional Context

No response

Debug Output

~\source\clap_bug on master  ● λ cargo run -- 0x11
   Compiling adler v1.0.2
   Compiling gimli v0.26.2
   Compiling cfg-if v1.0.0
   Compiling rustc-demangle v0.1.21
   Compiling memchr v2.5.0
   Compiling libc v0.2.137
   Compiling miniz_oxide v0.5.4
   Compiling object v0.29.0                                                                                   
   Compiling addr2line v0.17.0
   Compiling backtrace v0.3.66
   Compiling clap v4.0.24
   Compiling clap_bug v0.1.0 (C:\Users\vadim\source\clap_bug)
    Finished dev [unoptimized + debuginfo] target(s) in 5.74s
     Running `target\debug\clap_bug.exe 0x11`
Hello, world!
[      clap::builder::command]  Command::_do_parse
[      clap::builder::command]  Command::_build: name="clap_bug"
[      clap::builder::command]  Command::_propagate:clap_bug
[      clap::builder::command]  Command::_check_help_and_version:clap_bug expand_help_tree=false
[      clap::builder::command]  Command::long_help_exists
[      clap::builder::command]  Command::_check_help_and_version: Building default --help
[      clap::builder::command]  Command::_check_help_and_version: Building default --version
[      clap::builder::command]  Command::_propagate_global_args:clap_bug
[clap::builder::debug_asserts]  Command::_debug_asserts
[clap::builder::debug_asserts]  Arg::_debug_asserts:Payload
[clap::builder::debug_asserts]  Arg::_debug_asserts:help
[clap::builder::debug_asserts]  Arg::_debug_asserts:version
[clap::builder::debug_asserts]  Command::_verify_positionals
[        clap::parser::parser]  Parser::get_matches_with
[        clap::parser::parser]  Parser::get_matches_with: Begin parsing 'RawOsStr("0x11")' ([48, 120, 49, 49])
[        clap::parser::parser]  Parser::possible_subcommand: arg=Ok("0x11")
[        clap::parser::parser]  Parser::get_matches_with: sc=None
[        clap::parser::parser]  Parser::get_matches_with: Positional counter...1
[        clap::parser::parser]  Parser::get_matches_with: Low index multiples...false
[        clap::parser::parser]  Parser::resolve_pending: id="Payload"
[        clap::parser::parser]  Parser::react action=Append, identifier=Some(Index), source=CommandLine       
[        clap::parser::parser]  Parser::remove_overrides: id="Payload"
[   clap::parser::arg_matcher]  ArgMatcher::start_custom_arg: id="Payload", source=CommandLine
[      clap::builder::command]  Command::groups_for_arg: id="Payload"
[   clap::parser::arg_matcher]  ArgMatcher::start_custom_arg: id="Cli", source=CommandLine
[        clap::parser::parser]  Parser::push_arg_values: ["0x11"]
[        clap::parser::parser]  Parser::add_single_val_to_arg: cur_idx:=1
[   clap::parser::arg_matcher]  ArgMatcher::needs_more_vals: o=Payload, pending=0
[   clap::parser::arg_matcher]  ArgMatcher::needs_more_vals: expected=1..=18446744073709551615, actual=0      
[        clap::parser::parser]  Parser::react not enough values passed in, leaving it to the validator to complain
[        clap::parser::parser]  Parser::add_defaults
[        clap::parser::parser]  Parser::add_defaults:iter:Payload:
[        clap::parser::parser]  Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser]  Parser::add_default_value:iter:Payload: doesn't have default vals
[        clap::parser::parser]  Parser::add_defaults:iter:help:
[        clap::parser::parser]  Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser]  Parser::add_default_value:iter:help: doesn't have default vals
[        clap::parser::parser]  Parser::add_defaults:iter:version:
[        clap::parser::parser]  Parser::add_default_value: doesn't have conditional defaults
[        clap::parser::parser]  Parser::add_default_value:iter:version: doesn't have default vals
[     clap::parser::validator]  Validator::validate
[     clap::parser::validator]  Validator::validate_conflicts
[     clap::parser::validator]  Validator::validate_exclusive
[     clap::parser::validator]  Validator::validate_conflicts::iter: id="Payload"
[     clap::parser::validator]  Conflicts::gather_conflicts: arg="Payload"
[      clap::builder::command]  Command::groups_for_arg: id="Payload"
[     clap::parser::validator]  Conflicts::gather_direct_conflicts id="Payload", conflicts=[]
[     clap::parser::validator]  Conflicts::gather_direct_conflicts id="Cli", conflicts=[]
[     clap::parser::validator]  Conflicts::gather_conflicts: conflicts=[]
[     clap::parser::validator]  Validator::validate_required: required=ChildGraph([])
[     clap::parser::validator]  Validator::gather_requires
[     clap::parser::validator]  Validator::gather_requires:iter:"Payload"
[     clap::parser::validator]  Validator::gather_requires:iter:"Cli"
[     clap::parser::validator]  Validator::gather_requires:iter:"Cli":group
[     clap::parser::validator]  Validator::validate_required: is_exclusive_present=false
[   clap::parser::arg_matcher]  ArgMatcher::get_global_values: global_arg_vec=[]
thread 'main' panicked at 'Mismatch between definition and access of `Payload`. Could not downcast to u8, need to downcast to alloc::vec::Vec<u8>
', src\main.rs:11:14
stack backtrace:
   0: std::panicking::begin_panic_handler
             at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library\std\src\panicking.rs:584
   1: core::panicking::panic_fmt
             at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library\core\src\panicking.rs:142
   2: enum$<clap::parser::error::MatchesError, 1, 18446744073709551615, Downcast>::unwrap<enum$<core::option::Option<clap::parser::matches::arg_matches::Values<u8> >, 1, 18446744073709551615, Some> >
             at C:\Users\vadim\.cargo\registry\src\gh.neting.cc-1ecc6299db9ec823\clap-4.0.24\src\parser\error.rs:30
   3: clap::parser::matches::arg_matches::ArgMatches::remove_many<u8>
             at C:\Users\vadim\.cargo\registry\src\gh.neting.cc-1ecc6299db9ec823\clap-4.0.24\src\parser\matches\arg_matches.rs:338
   4: clap_bug::impl$2::from_arg_matches_mut
             at .\src\main.rs:7
   5: clap::derive::Parser::parse<clap_bug::Cli>
             at C:\Users\vadim\.cargo\registry\src\gh.neting.cc-1ecc6299db9ec823\clap-4.0.24\src\derive.rs:83   
   6: clap_bug::main
             at .\src\main.rs:16
   7: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
             at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52\library\core\src\ops\function.rs:248
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
error: process didn't exit successfully: `target\debug\clap_bug.exe 0x11` (exit code: 101)
@vslynko vslynko added the C-bug Category: Updating dependencies label Nov 14, 2022
@epage
Copy link
Member

epage commented Nov 14, 2022

clap determines what to do based on the wrapping type, in this case Vec. There isn't a way to opt-out and there isn't a guaranteed way for us to take the value parsers output type into account.

To work around this, you can fully qualify the type, like std::vec::Vec<u8>.

@epage epage added the A-derive Area: #[derive]` macro API label Nov 14, 2022
@fritzrehde
Copy link

I am having this issue as well. I get the following rust panic:

thread 'main' panicked at 'Mismatch between definition and access of `keybindings`. Could not downcast to TypeId { t: 8482930911198856167 }, need to downcast to TypeId { t: 12752778543207947612 }
', /home/fritz/.cargo/registry/src/.../clap-4.0.32/src/parser/error.rs:30:9

I have the following code snippet from my derived struct:

	/// Comma-seperated list of keybindings in the format KEY:OP[+OP]*[,KEY:OP[+OP]*]*
	#[arg(short = 'b', long = "bind", value_name = "KEYBINDINGS", value_delimiter = ',', value_parser = keybindings::parse_str)]
	keybindings: Option<Vec<(String, Vec<String>)>>,

This previously worked when Option<Vec<(String, Vec<String>)>> was just Vec<(String, Vec<String>)>. I assumed adding an option would just work out of the box. The behaviour I expected: if I don't specify the ---bind option keybindings will be none, otherwise it will be some of a vector delimited by value_delimiter and parsed by value_parser. Am I wrong in my assumption that this works?

@fritzrehde
Copy link

Here's some extra debug output running in the project instead of the binary:

thread 'main' panicked at 'Mismatch between definition and access of `keybindings`. Could not downcast to alloc::vec::Vec<(alloc::string::String, alloc::vec::Vec<alloc::string::String>)>, need to downcast to (alloc::string::String, alloc::vec::Vec<alloc::string::String>)
', src/config/mod.rs:195:18
stack backtrace:
   0: rust_begin_unwind
             at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panicking.rs:575:5
   1: core::panicking::panic_fmt
             at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/core/src/panicking.rs:65:14
   2: clap::parser::error::MatchesError::unwrap
             at /home/fritz/.cargo/registry/src/gh.neting.cc-1ecc6299db9ec823/clap-4.1.4/src/parser/error.rs:30:9
   3: clap::parser::matches::arg_matches::ArgMatches::remove_one
             at /home/fritz/.cargo/registry/src/gh.neting.cc-1ecc6299db9ec823/clap-4.1.4/src/parser/matches/arg_matches.rs:390:9
   4: <watchbind::config::ClapConfig as clap::derive::FromArgMatches>::from_arg_matches_mut
             at ./src/config/mod.rs:148:10
   5: clap::derive::Parser::parse
             at /home/fritz/.cargo/registry/src/gh.neting.cc-1ecc6299db9ec823/clap-4.1.4/src/derive.rs:83:19
   6: watchbind::config::Config::parse
             at ./src/config/mod.rs:24:13
   7: watchbind::main
             at ./src/main.rs:9:12
   8: core::ops::function::FnOnce::call_once
             at /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/core/src/ops/function.rs:251:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

@epage
Copy link
Member

epage commented Jan 30, 2023

btw I lost track of this being the issue for improving customizing the type, so we now have #4626 which has more information in that direction, so closing in favor of that issue.

@fritzrehde as your case is more of a support issue (helping debug), could you start a discussion and, at minimum, include the signature for keybindings::parse_str. If you could include a full reproduction case, that'd be even better.

@epage epage closed this as not planned Won't fix, can't repro, duplicate, stale Jan 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-derive Area: #[derive]` macro API C-bug Category: Updating dependencies
Projects
None yet
Development

No branches or pull requests

4 participants
@epage @vslynko @fritzrehde and others