Skip to content

Quoted values in make/local STANCFLAGS are split on whitespace and break direct stanc calls #1232

Description

@jgabry

This bug description was generated with the help of Claude

Describe the bug

get_cmdstan_flags("STANCFLAGS") splits the flag string on whitespace (R/utils.R):

flags_vec <- strsplit(x = trimws(flags), split = "\s+", perl = TRUE)[[1]]

That splits inside a quoted value. A make/local containing

STANCFLAGS += --include-paths='/my dir'

becomes:

#> [1] "--include-paths='/my" "dir'"

compile() appends this vector to the stanc options and then uses it two ways:

  • for make, the elements are rejoined with spaces into STANCFLAGS += ..., which round-trips fine — the shell re-strips the quotes;
  • for the direct stanc calls in get_standalone_hpp() (which relements are passed to processx as separate arguments, so stanc receives --include-paths='/my and dir' as two distinct argv e

stanc then treats dir' as a positional argument:

stanc: too many arguments, don't know what to do with model.s

Only compile() is affected — $check_syntax() and $format() don't read local STANCFLAGS.

To Reproduce

Put a quoted, space-containing value in make/local:

STANCFLAGS += --include-paths='/my dir'

then compile any model. The equivalent failure can be seen directly:

stanc <- file.path(cmdstan_path(), "bin", "stanc")
processx::run(stanc, c("--include-paths='/my", "dir'", "model.stan"),
              error_on_status = FALSE)$stderr
#> stanc: too many arguments, don't know what to do with model.stan

Expected behavior

Flags read from make/local should reach direct stanc calls asould produce — i.e. --include-paths=/my dir as one argument, with the shell quoting removed rather than treated as part of

Additional context

Pre-existing, not a regression. This is the same class of bug as #820 and #1227 (shell quoting leaking into processx arguments), but for flags coming from make/local rather than from include_paths or stanc_options. #1231 splits the direct and make-quoted option vectors but keeps passing the split local flags to both, so it doesn't cover this case.

Not a duplicate of #1230, which is the mirror image: #1230 is about the quoting cmdstanr writes for Make in include_paths_stanc3_args() and explicitly does not affect direct stanc calls. This one is about the quoting cmdstanr reads from make/local in get_cmdstan_flags(), and affects only the direct calls. Neither fix resolves the other — flags from make/local never pass through include_paths_stanc3_args().

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions