I observed a different between an interactive and non-interaction R session about traceback()
which I do not understand. For the code below, it will produce an error, but in an interactive R session, I can see the traceback information, whereas if I save the code to test.R
and call it via Rscript test.R
or R -f test.R
, I can no longer see the traceback:
f = function() {
on.exit(traceback())
1 + 'a'
}
f()
In an interactive R session:
> f = function() {
+ on.exit(traceback())
+ 1 + 'a'
+ }
> f()
Error in 1 + "a" : non-numeric argument to binary operator
1: f()
Non-interactive execution:
$ Rscript test.R
Error in 1 + "a" : non-numeric argument to binary operator
Calls: f
No traceback available
Execution halted
I did not see an explanation in ?traceback
, and I'm wondering if there is a way to enable traceback for non-interactive R sessions. Thanks!
The traceback() function prints the list of functions that were called before the error occurred. The functions are printed in reverse order. traceback() does not tell you where in the function the error occurred. In order to know which line causes the error, you may want to step through the function using debug().
In R Programming, there are basically two ways in which we can implement an error handling mechanism. Either we can directly call the functions like stop() or warning(), or we can use the error options such as “warn” or “warning. expression”.
With default values of its arguments, traceback()
will look for an object named .Traceback
in the baseenv()
for information on the call stack. It looks (from src/main/errors.c
) like .Traceback
is only created if, among other conditions, R_Interactive || haveHandler
, suggesting that this object is not created during non-interactive sessions. If there is no object named .Traceback
, you will get the message "No traceback available".
However, by passing a non-NULL value to the x
argument of traceback()
, one can obtain information about the call stack from a non-interactive session. With a non-zero integer value (indicating the number of calls to skip in the stack), c-level functions (R_GetTraceback
) are called to investigate the call stack instead of looking in .Traceback
.
So there are a couple ways to obtain traceback information in a non-interactive session:
f = function() {
on.exit(traceback(1))
1 + 'a'
}
f()
Or, setting options
as Brandon Bertelsen suggested
options(error=function()traceback(2))
The different values passed to x
in the two examples account for the different number of functions to skip
In the on.exit
example, traceback(1)
skips the call to traceback()
.
In the example setting options
, there is an extra anonymous function that calls traceback()
which should/could also be skipped.
In the example in the OP, there's not much more information gained by using traceback()
compared to the automatic traceback provided in the case of an error in a non-interactive session. However, with functions that take (and are passed) arguments, using traceback()
will be much more informative than the standard presentation of the call stack in the non-interactive session.
There is also the possibility to dump debugging information and load them later on. (See good ?debugger
help pages and comments on the topic)
via e.g.:
options(error = quote(dump.frames("testdump", TRUE)))
...
load("testdump.rda")
debugger(testdump)
or
options(error = quote({dump.frames(to.file = TRUE); q(status = 1)}))
BenBarnes's answer and dshepherd's comment are life saving. I will add one more parameter to avoid clogging up the screen in case one of the parameters is very big.
options(error=function(){traceback(2,max.lines=3);if(!interactive())quit("no",status=1,runLast=FALSE)})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With