Skip to content

Order of global arg usage changes behaviour with conflicts_with on Command arg #6160

@merc1031

Description

@merc1031

Please complete the following tasks

Rust Version

rustc 1.88.0 (6b00bc388 2025-06-23)

Clap Version

4.5.47

Minimal reproducible code

Also tested on rustplayground 1.90.0 https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=72c2c207bad9a0430a2c8b4ba331c4a8

use std::path::PathBuf;
use clap::{Parser};

#[derive(Parser, Debug)]
pub struct Args {
    #[clap(conflicts_with = "root")]
    pub path: Option<PathBuf>,
}

#[derive(Parser, Debug)]
enum Commands {
    Do(Args)
}

#[derive(Parser, Debug)]
pub struct Cli {
    #[command(subcommand)]
    pub command: Commands,
    #[arg(long, global = true)]
    pub root: Option<PathBuf>,
}


fn main() {
    let res  = Cli::try_parse_from(["app", "--root", ".",  "do", "."]);
    println!("{res:?}");
    let res  = Cli::try_parse_from(["app", "do", "--root", ".", "."]);
    println!("{res:?}");

}

Steps to reproduce the bug with the above code

Just run the playground https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=72c2c207bad9a0430a2c8b4ba331c4a8

Actual Behaviour

--root . do . Does not obey the conflicts_with
do --root . . Does obey the conflicts_with

Ok(Cli { command: Do(Args { path: Some(".") }), root: Some(".") })
Err(ErrorInner { kind: ArgumentConflict, context: FlatMap { keys: [InvalidArg, PriorArg, Usage], values: [String("--root <ROOT>"), String("[PATH]"), StyledStr(StyledStr("\u{1b}[1m\u{1b}[4mUsage:\u{1b}[0m \u{1b}[1mapp do\u{1b}[0m \u{1b}[1m--root\u{1b}[0m <ROOT> [PATH]"))] }, message: None, source: None, help_flag: Some("--help"), styles: Styles { header: Style { fg: None, bg: None, underline: None, effects: Effects(BOLD | UNDERLINE) }, error: Style { fg: Some(Ansi(Red)), bg: None, underline: None, effects: Effects(BOLD) }, usage: Style { fg: None, bg: None, underline: None, effects: Effects(BOLD | UNDERLINE) }, literal: Style { fg: None, bg: None, underline: None, effects: Effects(BOLD) }, placeholder: Style { fg: None, bg: None, underline: None, effects: Effects() }, valid: Style { fg: Some(Ansi(Green)), bg: None, underline: None, effects: Effects() }, invalid: Style { fg: Some(Ansi(Yellow)), bg: None, underline: None, effects: Effects() }, context: Style { fg: None, bg: None, underline: None, effects: Effects() }, context_value: None }, color_when: Auto, color_help_when: Auto, backtrace: None })

Expected Behaviour

--root . do . Does obey the conflicts_with
do --root . . Does obey the conflicts_with

Err(ErrorInner { kind: ArgumentConflict, context: FlatMap { keys: [InvalidArg, PriorArg, Usage], values: [String("--root <ROOT>"), String("[PATH]"), StyledStr(StyledStr("\u{1b}[1m\u{1b}[4mUsage:\u{1b}[0m \u{1b}[1mapp do\u{1b}[0m \u{1b}[1m--root\u{1b}[0m <ROOT> [PATH]"))] }, message: None, source: None, help_flag: Some("--help"), styles: Styles { header: Style { fg: None, bg: None, underline: None, effects: Effects(BOLD | UNDERLINE) }, error: Style { fg: Some(Ansi(Red)), bg: None, underline: None, effects: Effects(BOLD) }, usage: Style { fg: None, bg: None, underline: None, effects: Effects(BOLD | UNDERLINE) }, literal: Style { fg: None, bg: None, underline: None, effects: Effects(BOLD) }, placeholder: Style { fg: None, bg: None, underline: None, effects: Effects() }, valid: Style { fg: Some(Ansi(Green)), bg: None, underline: None, effects: Effects() }, invalid: Style { fg: Some(Ansi(Yellow)), bg: None, underline: None, effects: Effects() }, context: Style { fg: None, bg: None, underline: None, effects: Effects() }, context_value: None }, color_when: Auto, color_help_when: Auto, backtrace: None })
Err(ErrorInner { kind: ArgumentConflict, context: FlatMap { keys: [InvalidArg, PriorArg, Usage], values: [String("--root <ROOT>"), String("[PATH]"), StyledStr(StyledStr("\u{1b}[1m\u{1b}[4mUsage:\u{1b}[0m \u{1b}[1mapp do\u{1b}[0m \u{1b}[1m--root\u{1b}[0m <ROOT> [PATH]"))] }, message: None, source: None, help_flag: Some("--help"), styles: Styles { header: Style { fg: None, bg: None, underline: None, effects: Effects(BOLD | UNDERLINE) }, error: Style { fg: Some(Ansi(Red)), bg: None, underline: None, effects: Effects(BOLD) }, usage: Style { fg: None, bg: None, underline: None, effects: Effects(BOLD | UNDERLINE) }, literal: Style { fg: None, bg: None, underline: None, effects: Effects(BOLD) }, placeholder: Style { fg: None, bg: None, underline: None, effects: Effects() }, valid: Style { fg: Some(Ansi(Green)), bg: None, underline: None, effects: Effects() }, invalid: Style { fg: Some(Ansi(Yellow)), bg: None, underline: None, effects: Effects() }, context: Style { fg: None, bg: None, underline: None, effects: Effects() }, context_value: None }, color_when: Auto, color_help_when: Auto, backtrace: None })

Additional Context

No response

Debug Output

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-parsingArea: Parser's logic and needs it changed somehow.A-validatorsArea: ArgMatches validation logiC-bugCategory: bugS-triageStatus: New; needs maintainer attention.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions