Skip to content

fix: do not run checks against default values (#1375) - #1376

Closed
henryiii wants to merge 1 commit into
mainfrom
fix/1375-default-val-check
Closed

fix: do not run checks against default values (#1375)#1376
henryiii wants to merge 1 commit into
mainfrom
fix/1375-default-val-check

Conversation

@henryiii

@henryiii henryiii commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

🤖 AI text below 🤖

Fixes #1375.

Problem

add_option(...)->check(...)->default_val(...) throws immediately during app setup, not during parsing:

app.add_option("someNumber,-n,--someNumber", "Some number")
    ->check(CLI::PositiveNumber)
    ->default_val(0);   // terminate called after throwing 'CLI::ValidationError'

default_val() validated the default against every registered validator, so a default that fails a check() threw right there — outside the CLI11_PARSE try/catch, terminating the program. The behavior was also order-dependent: it only threw when the check() was registered before default_val().

Fix

Thread a transform_only flag through run_callback_validate_results_validate. When validating a default value, only modifying validators (transforms) are applied; non-modifying checks are skipped. This leans on the existing distinction that check() marks its validator non_modifying() while transform() does not.

Consequences:

Behavior change

default_val() no longer validates a default against check()s. One existing assertion in NumericTypeTest (a bad default caught by check(CLI::Number) at config time) was updated to reflect this, with added coverage that the check still fires on parsed input.

Tests

  • Added defaultValFailingCheck regression test (mirrors the issue MWE); confirmed it failed before the fix.
  • Updated doubleVectorFunctionRunCallbackOnDefault.
  • Documented the behavior in README.md and book/chapters/options.md.
  • Full suite passes (82/82); prek clean.

default_val() validated the default against all registered validators at
configuration time, so a default that failed a check() (e.g. 0 with
CLI::PositiveNumber) threw immediately during app setup — outside the
CLI11_PARSE try/catch. The throw was also order-dependent, only firing when
the check was registered before default_val().

Thread a transform_only flag through run_callback/_validate_results/_validate
so that validating a default applies only modifying validators (transforms),
skipping non-modifying checks. Transforms and conversion still run, so enum
defaults still convert and un-convertible defaults still raise ConversionError;
checks apply to parsed input and are caught by CLI11_PARSE as expected.

Assisted-by: ClaudeCode:claude-opus-4.8
@RL-S

RL-S commented Jul 2, 2026

Copy link
Copy Markdown

I think the default_val should still be checked against the registered validators - just not immediately, but during parsing. Not checking them at all would not be an improvement.

@henryiii

henryiii commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator Author

I was experimenting with this - actually registering deferred evaluations and running them during parsing would be a much bigger change. You control the default, though (and can manually call the validator), so I'm not sure if we should require the default be able to validate. It would mean you could set a default that can't be passed, but sometimes you might want that. (I'm a little surprised 0 is not a positive number, I'd have said it was both).

@phlptp

phlptp commented Jul 2, 2026 via email

Copy link
Copy Markdown
Collaborator

@RL-S

RL-S commented Jul 2, 2026

Copy link
Copy Markdown

In my case, the default value is a subdirectory of the working directory. That's a runtime value, so it requires validation. Passing the option allows changing the subdirectory's name, so I do require all cases.

(Including zero is typically called non-negative, which also has a builtin validator)

@henryiii henryiii closed this Jul 3, 2026
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.

add_option(...)->check(...)->default_val(...) throws immediately instead of when parsing

3 participants