Consider using rlang::abort()
If you use rlang::abort() instead of base::stop(), you'll be able to get much nicer call traces on error.
I'm poking at this. Here's example behavior for one stop() instance:
@hadley, are there better motivating use cases here that would highlight the improved functionality? Or do you only realize the benefits of abort if you intelligently use the .subclass and ... available in abort?
In case either of you are not aware, we do quite extensive work to try to get helpful stack traces in Shiny already: https://github.com/rstudio/shiny/wiki/Stack-traces-in-R
I forget exactly what you need to do, but you can get the full tree like this (reprex did it for me):
f <- function() g()
g <- function() try(h())
h <- function() rlang::abort("!")
f()
#> Error : !
#> Backtrace:
#> █
#> 1. └─global::f()
#> 2. └─global::g()
#> 3. ├─base::try(h())
#> 4. │ └─base::tryCatch(...)
#> 5. │ └─base:::tryCatchList(expr, classes, parentenv, handlers)
#> 6. │ └─base:::tryCatchOne(expr, names, parentenv, handlers[[1L]])
#> 7. │ └─base:::doTryCatch(return(expr), name, parentenv, handler)
#> 8. └─global::h()
Or you can request the simplification to the terminal branches:
print(rlang::last_trace(), simplify = "branch")
#> 1. global::f()
#> 2. global::g()
#> 8. global::h()
@jcheng5 I think we now have the tooling in rlang to supplant a lot of that custom work
(Oh, we don't do anything for errors that make it all the way to the top level, only for stack traces that are caught and printed without exiting Shiny.)
:+1: on this, it would be a great help for debugging deeply nested modular apps to be able to locate errors in functions that don't already use rlang::abort style error handling, such as any functions from the packages that come bundled with base (utils, stats etc).
I currently resort to using options(shiny.error = utils::recover) to locate the observer/reactive where the error occurred and intuit the source of the error from there, but that's not very precise. An rlang::trace_back for all the errors that occur in a shiny app would be amazing!
@yogat3ch Are you not already seeing complete stack traces, including source file names, line numbers, and reactive/observer names being emitted to the console? Can you show an example of the kind of stack traces you get when a non-rlang error is thrown?
@jcheng5 Most of the time shiny gives errors with extended stack traces and line numbers. On occasion, I'll get just an error. I'll provide a screenshot and context next time that occurs.
Hi @jcheng5,
It took a while for one to surface organically - here's an example that demonstrates how a base::switch call nested deeply in a modularized shiny app doesn't provide any trace back context:

Is there a way to make the links clickable?