This bug description was generated with the help of Claude
Describe the bug
compile() builds stanc_built_options with single quotes around named option
values (R/model.R:719):
stanc_built_options <- c(stanc_built_options, paste0("--", option_name, "=", "'", stanc_options[[i]], "'"))
That quoting is correct for the STANCFLAGS += ... string handed to make, but the
same vector (stancflags_combined) is then passed straight to processx via
get_standalone_hpp() at R/model.R:728-731:
stancflags_standalone <- c("--standalone-functions", stanc_inc_paths, stancflags_combined)
self$functions$hpp_code <- get_standalone_hpp(temp_stan_file, stancflags_standalone)
private$model_methods_env_ <- new.env()
private$model_methods_env_$hpp_code_ <- get_standalone_hpp(temp_stan_file, c(stanc_inc_paths, stancflags_combined))
There is no shell in that path, so stanc receives the quotes as literal
characters and rejects the value. get_standalone_hpp() returns NULL
invisibly on failure, and the NULL blows up downstream.
This affects any named, non-logical stanc_option other than name (which is
already special-cased at R/model.R:716). Lines 728-731 run on every compile,
not only when compile_standalone = TRUE.
This is the same class of bug as #820 (fixed in #1226 for include paths), just
for option values rather than include paths.
To Reproduce
library(cmdstanr)
d <- tempdir()
f <- file.path(d, "m.stan")
writeLines(c(
"functions { real half(real x) { return x/2; } }",
"parameters { real y; }",
"model { y ~ std_normal(); }"
), f)
mod <- cmdstan_model(f, stanc_options = list(canonicalize = "deprecations"))
#> Error in writeLines(private$model_methods_env_$hpp_code_, con = wsl_safe_path(private$hpp_file_, :
#> can only write character objects
The underlying stanc rejection, confirmed by invoking the binary directly:
stanc <- file.path(cmdstan_path(), "bin", "stanc")
processx::run(stanc, c(f, "--auto-format", "--canonicalize='deprecations'"),
error_on_status = FALSE)$stderr
#> stanc: option --canonicalize: invalid element in list ('deprecations'): invalid ...
Passing the same option unquoted (--canonicalize=deprecations) succeeds.
Expected behavior
Compilation succeeds and stanc receives --canonicalize=deprecations. Quoting
should be applied only on the make/STANCFLAGS path, matching how include paths
are handled by the standalone_call argument of include_paths_stanc3_args().
Secondarily: a failure inside get_standalone_hpp() should surface as a real
error rather than a silent NULL that produces "can only write character
objects" several frames later.
*** Additional context
Found while reviewing #1226. Not introduced by that PR — present on master.
This bug description was generated with the help of Claude
Describe the bug
compile()buildsstanc_built_optionswith single quotes around named optionvalues (
R/model.R:719):That quoting is correct for the
STANCFLAGS += ...string handed to make, but thesame vector (
stancflags_combined) is then passed straight toprocessxviaget_standalone_hpp()atR/model.R:728-731:There is no shell in that path, so
stancreceives the quotes as literalcharacters and rejects the value.
get_standalone_hpp()returnsNULLinvisibly on failure, and the
NULLblows up downstream.This affects any named, non-logical
stanc_optionother thanname(which isalready special-cased at
R/model.R:716). Lines 728-731 run on every compile,not only when
compile_standalone = TRUE.This is the same class of bug as #820 (fixed in #1226 for include paths), just
for option values rather than include paths.
To Reproduce
The underlying stanc rejection, confirmed by invoking the binary directly:
Passing the same option unquoted (--canonicalize=deprecations) succeeds.
Expected behavior
Compilation succeeds and stanc receives --canonicalize=deprecations. Quoting
should be applied only on the make/STANCFLAGS path, matching how include paths
are handled by the standalone_call argument of include_paths_stanc3_args().
Secondarily: a failure inside get_standalone_hpp() should surface as a real
error rather than a silent NULL that produces "can only write character
objects" several frames later.
*** Additional context
Found while reviewing #1226. Not introduced by that PR — present on master.