Skip to content

rlang internal error when interacting with R.utils::withTimeout #2241

@MichaelChirico

Description

@MichaelChirico

I haven't been able to get this more minimal than the following; I don't understand well what's gone wrong:

foo <- function(formula, timeout = Inf) {
  bar <- function() {
    R.utils::withTimeout(
      {Sys.sleep(2 * timeout); lm(formula, iris)},
      timeout = timeout,
      onTimeout = "error"
    )
  }
  bar()
}

expect_error(foo(Sepal.Length ~ Sepal.Width, timeout = 1), "elapsed")
# Error in .subset2(cnd, "rlang") : subscript out of bounds

The traceback is:

19: cnd_some(cnd, function(x) !is_null(x[["trace"]]))
18: cnd_entrace(cnd)
17: (function (cnd) 
    {
        if (!is.null(matched) || !matches(cnd)) {
            return()
        }
        if (can_entrace(cnd)) {
            cnd <- cnd_entrace(cnd)
        }
        matched <<- cnd
        if (inherits(cnd, "message") || inherits(cnd, "warning")) {
            cnd_muffle(cnd)
        }
        else if (inherits(cnd, "error") || inherits(cnd, "skip")) {
            return_from(tl, cnd)
        }
    })(structure(NA, .env = <environment>, class = c("TimeoutException", 
    "Exception", "simpleError", "error", "condition", "try-error", 
    "Object")))
16: signalCondition(this)
15: throw.Exception(ex)
14: throw(ex)
13: value[[3L]](cond)
12: tryCatchOne(expr, names, parentenv, handlers[[1L]])
11: tryCatchList(expr, classes, parentenv, handlers)
10: tryCatch({
        eval(expr, envir = envir, enclos = baseenv())
    }, error = function(ex) {
        msg <- ex$message
        pattern <- gettext("reached elapsed time limit", "reached CPU time limit", 
            domain = "R")
        pattern <- paste(pattern, collapse = "|")
        if (regexpr(pattern, msg) != -1L) {
            ex <- TimeoutException(msg, cpu = cpu, elapsed = elapsed)
            if (onTimeout == "error") {
                throw(ex)
            }
            else if (onTimeout == "warning") {
                warning(getMessage(ex))
                NULL
            }
            else if (onTimeout == "silent") {
                NULL
            }
        }
        else {
            throw(ex)
        }
    })
9: R.utils::withTimeout({
       Sys.sleep(2 * timeout)
       lm(formula, iris)
   }, timeout = timeout, onTimeout = "error") at #3
8: bar() at #9
7: foo(Sepal.Length ~ Sepal.Width, timeout = 1)
6: eval_bare(quo_get_expr(.quo), quo_get_env(.quo))
5: withCallingHandlers(expr, condition = function(cnd) {
       if (!is.null(matched) || !matches(cnd)) {
           return()
       }
       if (can_entrace(cnd)) {
           cnd <- cnd_entrace(cnd)
       }
       matched <<- cnd
       if (inherits(cnd, "message") || inherits(cnd, "warning")) {
           cnd_muffle(cnd)
       }
       else if (inherits(cnd, "error") || inherits(cnd, "skip")) {
           return_from(tl, cnd)
       }
   })
4: .capture(act$val <- eval_bare(quo_get_expr(.quo), quo_get_env(.quo)), 
       ...)
3: quasi_capture(enquo(object), label, capture_matching_condition, 
       matches = matcher)
2: expect_condition_matching("error", {
       {
           object
       }
   }, regexp = regexp, class = class, ..., inherit = inherit, info = info, 
       label = label)
1: expect_error(foo(Sepal.Length ~ Sepal.Width, timeout = 1), "elapsed")

cnd in rlang:::cnd_some() is:

trace(rlang:::cnd_some, at=1, quote(message(toString(class(cnd)))))
expect_error(foo(Sepal.Length ~ Sepal.Width, timeout = 1), "elapsed")
# TimeoutException, Exception, simpleError, error, condition, try-error, Object
untrace(rlang:::cnd_some)

The same comes from trying to catch the exception class directly instead:

expect_condition(foo(Sepal.Length ~ Sepal.Width, timeout = 1), class = "TimeoutException")
# Error in .subset2(cnd, "rlang") : subscript out of bounds

For now, I'm directly using tryCatch() as a workaroud:

expect_true(tryCatch(foo(Sepal.Length ~ Sepal.Width, timeout = 1), TimeoutException = \(e) TRUE))

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions