Is it possible to suppress the chain of 'caused by' output when handling an exception?

When handling an exception that was ‘caused by’ another exception, Julia prints out a stack of exceptions. Normally this is helpful, but in this case I want to handle the exception, and give the user a helpful message. I can do this, but after my error message is printed, there is the original exception which (in this case) makes it harder for the user to find the message I want them to see.

For example

julia> function foo()
       try
       Base.require(Main, :NCDatasets)
       catch
       error("To handle this error, do X")
       end
       end
foo (generic function with 1 method)

julia> foo()
ERROR: To handle this error, do X
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:35
 [2] foo()
   @ Main ./REPL[11]:5
 [3] top-level scope
   @ REPL[12]:1

caused by: ArgumentError: Package NCDatasets not found in current path, maybe you meant `import/using .NCDatasets`.
- Otherwise, run `import Pkg; Pkg.add("NCDatasets")` to install the NCDatasets package.
Stacktrace:
 [1] macro expansion
   @ ./loading.jl:1630 [inlined]
 [2] macro expansion
   @ ./lock.jl:267 [inlined]
 [3] require(into::Module, mod::Symbol)
   @ Base ./loading.jl:1611
 [4] foo()
   @ Main ./REPL[11]:3
 [5] top-level scope
   @ REPL[12]:1

How can I get rid of the caused by: ArgumentError block (which in my actual use case has a long stack trace which pushes my error message off the top of the screen)?

PS I do want to raise an error that stops execution (but does not exit Julia) from far down a call stack, so I do not want (for example) to just print a message and return from the function.

Edit: I thought you were asking a different question. One second …

Is this related to the difference between throw and rethrow? I’m a little bit unclear on that myself

1 Like

Yes, rethrow is one option here. But: the docs admonish you about not using it because it “lies” about what caused the problem :slight_smile:

The alternative form rethrow(e) allows you to associate an alternative exception object e with the current backtrace. However this misrepresents the program state at the time of the error so you’re encouraged to instead throw a new exception using throw(e).

julia> function foo()
       try
       Base.require(Main, :NCDatasets)
       catch ex
       rethrow(ArgumentError("To handle this error, do X"))
       end
       end
foo (generic function with 1 method)

julia> foo()
ERROR: ArgumentError: To handle this error, do X
Stacktrace:
 [1] macro expansion
   @ ./loading.jl:1630 [inlined]
 [2] macro expansion
   @ ./lock.jl:267 [inlined]
 [3] require(into::Module, mod::Symbol)
   @ Base ./loading.jl:1611
 [4] foo()
   @ Main ./REPL[17]:3
 [5] top-level scope
   @ REPL[18]:1

^^ This stack trace points at require, not the catch block of foo()!

2 Likes