Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 40 additions & 7 deletions R/fit.R
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,28 @@ CmdStanFit <- R6::R6Class(
init_ = NULL,
profiles_ = NULL,
model_methods_env_ = NULL,
return_codes_ = NULL
return_codes_ = NULL,
read_cmdstan_csv_with_cache_hint_ = function(...) {
tryCatch(
read_cmdstan_csv(...),
error = function(e) {
err_msg <- conditionMessage(e)
if (isTRUE(getOption("knitr.in.progress")) &&
isTRUE(self$runset$args$using_tempdir) &&
Copy link
Copy Markdown
Member Author

@jgabry jgabry Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we do it here instead of inside read_cmdstan_csv() we can access the internal using_tempdir flag, which is more reliable than checking getOption(cmdstan_output_dir) because the option may have changed between the initial quarto caching and the later re-rendering (so it's not a 100% reliable indicator of whether the temp directory was used).

grepl("File does not exist:", err_msg, fixed = TRUE)) {
stop(
paste0(
err_msg,
"\n If this error happened during a cached Quarto or R Markdown render,\n",
" see `cmdstanr_output_dir` in `?cmdstanr_global_options`"
),
call. = FALSE
)
}
stop(e)
}
)
}
)
)

Expand Down Expand Up @@ -1432,7 +1453,7 @@ CmdStanMCMC <- R6::R6Class(
if (!length(self$output_files(include_failed = FALSE))) {
stop("No chains finished successfully. Unable to retrieve the draws.", call. = FALSE)
}
csv_contents <- read_cmdstan_csv(
csv_contents <- private$read_cmdstan_csv_with_cache_hint_(
files = self$output_files(include_failed = FALSE),
variables = variables,
sampler_diagnostics = sampler_diagnostics,
Expand Down Expand Up @@ -1904,7 +1925,10 @@ CmdStanMLE <- R6::R6Class(
if (!length(self$output_files(include_failed = FALSE))) {
stop("Optimization failed. Unable to retrieve the draws.", call. = FALSE)
}
csv_contents <- read_cmdstan_csv(self$output_files(), format = format)
csv_contents <- private$read_cmdstan_csv_with_cache_hint_(
files = self$output_files(),
format = format
)
private$draws_ <- csv_contents$point_estimates
private$metadata_ <- csv_contents$metadata
invisible(self)
Expand Down Expand Up @@ -2014,7 +2038,10 @@ CmdStanLaplace <- R6::R6Class(
if (!length(self$output_files(include_failed = FALSE))) {
stop("Laplace inference failed. Unable to retrieve the draws.", call. = FALSE)
}
csv_contents <- read_cmdstan_csv(self$output_files(), format = format)
csv_contents <- private$read_cmdstan_csv_with_cache_hint_(
files = self$output_files(),
format = format
)
private$draws_ <- csv_contents$draws
private$metadata_ <- csv_contents$metadata
invisible(self)
Expand Down Expand Up @@ -2097,7 +2124,10 @@ CmdStanVB <- R6::R6Class(
if (!length(self$output_files(include_failed = FALSE))) {
stop("Variational inference failed. Unable to retrieve the draws.", call. = FALSE)
}
csv_contents <- read_cmdstan_csv(self$output_files(), format = format)
csv_contents <- private$read_cmdstan_csv_with_cache_hint_(
files = self$output_files(),
format = format
)
private$draws_ <- csv_contents$draws
private$metadata_ <- csv_contents$metadata
invisible(self)
Expand Down Expand Up @@ -2165,7 +2195,10 @@ CmdStanPathfinder <- R6::R6Class(
if (!length(self$output_files(include_failed = FALSE))) {
stop("Pathfinder failed. Unable to retrieve the draws.", call. = FALSE)
}
csv_contents <- read_cmdstan_csv(self$output_files(), format = format)
csv_contents <- private$read_cmdstan_csv_with_cache_hint_(
files = self$output_files(),
format = format
)
private$draws_ <- csv_contents$draws
private$metadata_ <- csv_contents$metadata
invisible(self)
Expand Down Expand Up @@ -2283,7 +2316,7 @@ CmdStanGQ <- R6::R6Class(
if (!length(self$output_files(include_failed = FALSE))) {
stop("Generating quantities for all MCMC chains failed. Unable to retrieve the generated quantities.", call. = FALSE)
}
csv_contents <- read_cmdstan_csv(
csv_contents <- private$read_cmdstan_csv_with_cache_hint_(
files = self$output_files(include_failed = FALSE),
variables = variables,
sampler_diagnostics = "",
Expand Down
3 changes: 3 additions & 0 deletions R/options.R
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
#' CSV files when fitting models. The default is a temporary directory. Files in
#' a temporary directory are removed as part of \R garbage collection, while
#' files in an explicitly defined directory are not automatically deleted.
#' Note that using caching with R Markdown or Quarto does not store files from a
#' temporary directory, so we recommend setting `cmdstanr_output_dir` to avoid
#' failures when re-rendering.
#'
#' * `cmdstanr_verbose`: Should more information be printed
#' when compiling or running models, including showing how CmdStan was called
Expand Down
3 changes: 3 additions & 0 deletions man/cmdstanr_global_options.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions tests/testthat/test-fit-mcmc.R
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,35 @@ test_that("draws() method returns draws_array (reading csv works)", {
expect_equal(posterior::variables(draws_beta_alpha), c("beta[1]", "beta[2]", "beta[3]", "alpha"))
})

test_that("draws() errors with Quarto cache message when temp files are missing", {
# https://github.com/stan-dev/cmdstanr/issues/1012
# https://github.com/stan-dev/cmdstanr/pull/1176

fit <- testing_fit("logistic", method = "sample", seed = 123, chains = 1)
csv_files <- fit$output_files()

# Simulate a later cached re-render: the fit object still points to the temp
# output files, which don't exist anymore
unlink(csv_files, force = TRUE)
withr::local_options(list(
# Even if cmdstanr_output_dir is now set to a non-temp directory,
# it was not set when the fit was created so we should still get the error message
# that mentions cached Quarto or R Markdown renders.
cmdstanr_output_dir = test_path("resources"),
knitr.in.progress = TRUE
))

expect_error(
fit$draws(),
paste0(
"Assertion on 'files' failed: File does not exist: '", csv_files[[1]], "'.\n",
" If this error happened during a cached Quarto or R Markdown render,\n",
" see `cmdstanr_output_dir` in `?cmdstanr_global_options`"
),
fixed = TRUE
)
})

test_that("inv_metric() method works after mcmc", {
x <- fit_mcmc_1$inv_metric()
expect_length(x, fit_mcmc_1$num_chains())
Expand Down
Loading