Skip to content

Improve error messages for missing required input arguments#4389

Open
samuelbharti wants to merge 3 commits into
rstudio:mainfrom
samuelbharti:samuelbharti/review-shiny-issue-1423
Open

Improve error messages for missing required input arguments#4389
samuelbharti wants to merge 3 commits into
rstudio:mainfrom
samuelbharti:samuelbharti/review-shiny-issue-1423

Conversation

@samuelbharti
Copy link
Copy Markdown
Contributor

@samuelbharti samuelbharti commented May 28, 2026

Fixes #1423.

Summary

Input constructors (textInput(), sliderInput(), selectInput(), actionButton(), etc.) currently surface cryptic downstream R errors like argument "label" is missing, with no default when a required argument is omitted, without naming the function or the argument that was actually missing.

This PR adds a small internal check_required() helper in R/input-utils.R that uses eval(call("missing", ...), envir = caller_env()) to detect unsupplied promises without forcing them, then raises a classed error via cli::cli_abort() that names both the calling function and the missing argument(s). The helper is wired into the top of every *Input() constructor plus actionButton() / actionLink() for arguments without defaults (inputId, label, plus per-function specifics such as choices, min/max/value, data).

The error carries class shiny_missing_arg_error so downstream code can catch it specifically. Explicit NULL and NA are treated as "supplied" so documented opt-outs like label = NULL continue to work. No public API changes; only the error wording changes for the previously-broken cases.

Scope

In scope: every standalone input constructor and actionButton() / actionLink() — 15 functions in total.

Out of scope (intentionally):

  • Argument type validation (e.g., rejecting inputId = c("a", "b")). The issue is about clearer missing-arg messages, not a general validator.
  • Positional-shift heuristics. sliderInput("forgot my id!", 1, 10, 5) will still report value as missing because we can't infer the user's intent.
  • The update*Input() family. Same problem exists there but the surface area is larger; tracked as a follow-up.

Follow-ups

  • Apply the same check_required() treatment to updateTextInput(), updateSliderInput(), updateSelectInput(), etc.
  • Consider exporting check_required() (or replacing with rlang::check_required()) if other parts of shiny adopt the pattern.

Verification

Before:

sliderInput("Whoops forgot my id!", 1, 10, 5)
#> Error in force(default) : argument "value" is missing, with no default
textInput("text")
#> Error in label %AND% tags$label(label, `for` = inputId) :
#>   argument "label" is missing, with no default

After:

sliderInput("Whoops forgot my id!", 1, 10, 5)
#> Error in `sliderInput()`:
#> ! `sliderInput()` is missing required argument: `value`.
textInput("text")
#> Error in `textInput()`:
#> ! `textInput()` is missing required argument: `label`.
textInput()
#> Error in `textInput()`:
#> ! `textInput()` is missing required arguments: `inputId` and `label`.

Test plan

  • tests/testthat/test-input-required-args.R adds 7 test_that() blocks (48 expectations) covering: the helper's own behavior, the new error class, behavior under do.call(), regex-based regression assertions, explicit-NULL opt-out, happy-path shiny.tag returns for all 15 patched constructors, and full-message snapshots.
  • devtools::test(filter = "input"): 231 PASS, 0 FAIL.
  • Full devtools::test() suite earlier: 2018 PASS, 0 FAIL (12 environmental skips, unrelated).

@samuelbharti samuelbharti marked this pull request as ready for review May 28, 2026 18:35
Input constructors (textInput(), sliderInput(), selectInput(),
actionButton(), etc.) now report which function and which argument were
missing instead of surfacing a downstream R error like
'argument "label" is missing, with no default'.

Adds an internal check_required() helper in R/input-utils.R that uses
rlang::is_missing() against the caller's frame and cli::cli_abort() to
name both the function and the missing argument(s). The helper is wired
into the top of every *Input() constructor and actionButton() /
actionLink() for arguments without defaults.

Fixes rstudio#1423.
- Replace nested rlang call construction with eval(call("missing", ...))
  for readability; behavior unchanged.
- Classed error: cli_abort() now raises with class
  "shiny_missing_arg_error" so callers can catch it specifically.
- Test additions: verify the classed error, verify behavior under
  do.call(), and tighten happy-path assertions to confirm each
  constructor returns a shiny.tag.
Match the existing cadence for issue-reporter credits, e.g.
"(thanks @ismirsehregal, rstudio#4318)" on NEWS.md:177.
@samuelbharti samuelbharti force-pushed the samuelbharti/review-shiny-issue-1423 branch from 1193f11 to 81af13b Compare May 28, 2026 18:37
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.

More informative error messages when a required param is missing from the input* functions

1 participant