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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions