rerror-handling

get stack trace on tryCatch'ed error in R


This is related to some other questions, but I can't seem to figure out how to apply the answer, so I'm asking a new question.

I'm trying to figure out an uninformative error from a piece of code that looks like this:

tryCatch(MainLoop(), 
  error=function(e) { fatal(lgr, paste('caught fatal error:', as.character(e))); 
                      exit.status <<- 1 })

The problem is that the error appears to be related to something buried in a library function:

Error in nrow(x): (subscript) logical subscript too long

That nrow is not in my code, as the C-level error above only applies to a type of indexing that never happens in any of my nrow calls.

So I'd really like to get a stack trace from within that tryCatch. Here's an analogous problem:

x <- function() { y(); }
y <- function() { z(); }
z <- function() { stop("asdf") }

> x()
Error in z() : asdf
> tryCatch(x(), error=function(e) { print(conditionCall(e)) } )
z()
> tryCatch(x(), error=function(e) { dump.frames() } )
> last.dump
$`tryCatch(x(), error = function(e) {
    dump.frames()
})`
<environment: 0x1038e43b8>

$`tryCatchList(expr, classes, parentenv, handlers)`
<environment: 0x1038e4c60>

$`tryCatchOne(expr, names, parentenv, handlers[[1]])`
<environment: 0x1038e4918>

$`value[[3]](cond)`
<environment: 0x1038ea578>

attr(,"error.message")
[1] "asdf"
attr(,"class")
[1] "dump.frames"

How do I get the stack trace that includes the call to y()? Do I have to stop using tryCatch? What's a better way?


Solution

  • For interactive use one might trace(stop, quote(print(sys.calls()))) to print the call stack at the time stop() is invoked.

    From ?tryCatch,

     The function 'tryCatch' evaluates its expression argument in a
     context where the handlers provided in the '...'  argument are
     available.
    

    whereas

     Calling handlers are established by 'withCallingHandlers'...
     the handler is called... in the context where the condition
     was signaled...
    

    so

    >     withCallingHandlers(x(), error=function(e) print(sys.calls()))
    [[1]]
    withCallingHandlers(x(), error = function(e) print(sys.calls()))
    
    [[2]]
    x()
    
    [[3]]
    y()
    
    [[4]]
    z()
    
    [[5]]
    stop("asdf")
    
    [[6]]
    .handleSimpleError(function (e) 
    print(sys.calls()), "asdf", quote(z()))
    
    [[7]]
    h(simpleError(msg, call))
    
    Error in z() : asdf
    

    This is thwarted if there is an inner tryCatch

    withCallingHandlers({
        tryCatch(x(), error=function(e) stop("oops"))
    }, error=function(e) print(sys.calls()))
    

    as we only have access to the call stack after the tryCatch has 'handled' the error.