Skip to content

$variables() and $code() return stale results after the Stan file is edited and recompiled #1228

Description

@jgabry

This bug report was written with the assistance of Claude

Describe the bug

CmdStanModel caches private$variables_ on first $variables() call
(R/model.R:894) and private$stan_code_ at construction (R/model.R:263).
Neither is invalidated by $compile(), and stan_code_ is only ever refreshed
by $format(overwrite_file = TRUE) (R/model.R:1182).

So if the underlying .stan file changes and the model is recompiled through the
same object, $variables() and $code() keep describing the old program while
the executable is the new one. This is not just cosmetic: the fitting methods use
self$variables() for init/data checking, so they validate against the wrong
parameter set.

To Reproduce

library(cmdstanr)

d <- tempdir()
f <- file.path(d, "m.stan")
writeLines(c("parameters { real alpha; }", "model { alpha ~ std_normal(); }"), f)

mod <- cmdstan_model(f)
names(mod$variables()$parameters)
#> [1] "alpha"

# edit the model, then recompile through the same object
writeLines(c("parameters { real beta; }", "model { beta ~ std_normal(); }"), f)
mod$compile(force_recompile = TRUE)

names(mod$variables()$parameters)
#> [1] "alpha"          # stale
mod$code()
#> [1] "parameters { real alpha; }" "model { alpha ~ std_normal(); }"   # stale

fit <- mod$sample(chains = 1, iter_sampling = 100, iter_warmup = 100, refresh = 0)
posterior::variables(fit$draws())
#> [1] "lp__" "beta"          # the exe really is the new model

# a freshly constructed object is correct
names(cmdstan_model(f, compile = FALSE)$variables()$parameters)
#> [1] "beta"

Concrete user-visible falloutsupplying a correct init for the new model
produces a spurious warning naming the old parameter:

mod$sample(chains = 1, iter_sampling = 100, iter_warmup = 100, refresh = 0,
           init = list(list(beta = 0)))
#> Init values were only set for a subset of parameters.
#> Missing init values for the following parameters:
#> alpha

Expected behavior

$compile() should invalidate private$variables_ and re-read
private$stan_code_ so that $variables(), $code(), and the init/data checks
in the fitting methods reflect the program that was actually compiled.

Operating system
macOS 15.4

** CmdStanR version number**
0.9.0.9001 (dev), CmdStan 2.39.0

Additional context
Noticed while reviewing #1226. Unrelated to that PR's changes; the caching code
is untouched by it. One side effect of the variables_ cache is that the
"pre and post compilation" assertion in the $variables() works with #includes
test is vacuous — vars_post is just the cached vars_pre. Worth revisiting
that test alongside a fix.

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