# Intercepting error messages - HOW?

**URL:** <https://discourse.julialang.org/t/intercepting-error-messages-how/77189>\
**Category:** General Usage\
**Tags:** question, error-message\
**Created:** [February 28, 2022, 2:21pm UTC](https://discourse.julialang.org/t/intercepting-error-messages-how/77189 "2022-02-28T14:21:13Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![FedeClaudi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fedeclaudi/32/33490_2.png) [@FedeClaudi](https://discourse.julialang.org/u/FedeClaudi)\
**Post date:** [February 28, 2022, 2:21pm UTC](https://discourse.julialang.org/t/intercepting-error-messages-how/77189/1 "2022-02-28T14:21:13Z")

</div>

In my [Term.jl](https://github.com/FedeClaudi/Term.jl) project I aim to provide functionality to print nicely formatted, pretty, error messages. A preview:

![image](https://global.discourse-cdn.com/julialang/original/3X/3/7/3784111c57b2763567a5ded32b5d6f403d5945de.png)

This is inspired by [Rich](https://github.com/Textualize/rich) in python that prints error stacks like:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/6/8/686bb67f1a8fc10d56434b92888ff60dd8ee64f8.jpeg)

In python you can [define an `exception hook`](https://github.com/FedeClaudi/pyinspect/blob/02b9661eb90e75e55586b2627f79f2868276bee6/pyinspect/exceptions.py#L122) such that all errors go through it and you can print them as you’d like. I would like to the same in Julia, but haven’t found a way yet.

I haven’t found good docs on how errors are handled internally, but going through the code I’ve found functions like [`show_backtrace`](https://github.com/JuliaLang/julia/blob/befe38f18641d0e49c3de81ae9ca21d1941cfd95/base/errorshow.jl#L753) and `showerror` in `Base.errorshow.jl` and [`display_error`](https://github.com/JuliaLang/julia/blob/2338f5d3040ced10d69f4d15cca5fdca03364d9a/base/client.jl#L101) in `Base.client.jl` as well as other similarly named functions.

I can re-define this to print out formatted error messages as above, but there’s several things I’m not clear with:

1. what calls `show_backtrace` and `errorshow`? Does it depend on where the code is run (e.g. in VSCode or in the Julia app?). I can re-define `show-backtrace` and `errorshow`, but ideally I’d like to intercept error messages before.
2. what prints out `LoadError`s? It seems to bypass `show_backtrace` and `errorshow` as I can’t find a way to style that.
3. Accessing locals: in python’s exceptions hook you have access to locals at all levels in the callstack (see second image above). I know there’s `Base.@locals` but that only gives the locals where the macro is used. Is there a way to get locals at each frame in a `stacktrace` or `backtrace`?
4. Julia’s errors come with hints provided by `Base.Experimental.show_error_hints`, which is really nice. However when I try to use `show_error_hints` in my re-defined `errorshow` functions it doesn’t give any hint (it returns `nothing`). Is there a way to access error hints?

Thank you in advance for any help!

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [February 28, 2022, 3:03pm UTC](https://discourse.julialang.org/t/intercepting-error-messages-how/77189/2 "2022-02-28T15:03:54Z")

</div>

> [@FedeClaudi](#):
>
> what calls `show_backtrace` and `errorshow` ? Does it depend on where the code is run (e.g. in VSCode or in the Julia app?). I can re-define `show-backtrace` and `errorshow` , but ideally I’d like to intercept error messages before.

Yes, it depends on the IDE. In the REPL it’s handled by the following line: [https://github.com/JuliaLang/julia/blob/2338f5d3040ced10d69f4d15cca5fdca03364d9a/stdlib/REPL/src/REPL.jl#L291](https://github.com/JuliaLang/julia/blob/2338f5d3040ced10d69f4d15cca5fdca03364d9a/stdlib/REPL/src/REPL.jl#L291). Note however that refining any of these functions is type piracy and strongly discouraged, since it can result in inconsistent behavior and excessive invalidations. `Base.Experimental.register_error_hint` is how additional hints are intended to be added.

> [@FedeClaudi](#):
>
> what prints out `LoadError` s? It seems to bypass `show_backtrace` and `errorshow` as I can’t find a way to style that.

They should go through the REPL as well. Do you have an example?

> [@FedeClaudi](#):
>
> Accessing locals: in python’s exceptions hook you have access to locals at all levels in the callstack (see second image above). I know there’s `Base.@locals` but that only gives the locals where the macro is used. Is there a way to get locals at each frame in a `stacktrace` or `backtrace` ?

Yes, `@locals` always needs to be inserted into the source code. Otherwise you can’t access all locals inside a function unless you use an interpreter like [GitHub - JuliaDebug/JuliaInterpreter.jl: Interpreter for Julia code](https://github.com/JuliaDebug/JuliaInterpreter.jl)

> [@FedeClaudi](#):
>
> Julia’s errors come with hints provided by `Base.Experimental.show_error_hints` , which is really nice. However when I try to use `show_error_hints` in my re-defined `errorshow` functions it doesn’t give any hint (it returns `nothing` ). Is there a way to access error hints?

`show_error_hints` always returns `nothing`, the hints are printed to the supplied IO object. You can of course use `sprint` to get the output as a string or take a look at its source code if you want each separate hint.

---

<div class="post-metadata">

**Author:** ![FedeClaudi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fedeclaudi/32/33490_2.png) [@FedeClaudi](https://discourse.julialang.org/u/FedeClaudi)\
**Post date:** [February 28, 2022, 3:10pm UTC](https://discourse.julialang.org/t/intercepting-error-messages-how/77189/3 "2022-02-28T15:10:03Z")

</div>

Thank you, that’s very helpful!

> Note however that refining any of these functions is type piracy and strongly discouraged

Arrrr!

I would very much prefer not having to do that! But is there an alternative to it like python’s exception hook?  
If lines like `Base.invokelatest(Base.display_error, errio, val)` that you’ve send above (and similar ones e.g. in VSCode’s Julia Extension) are what prints out the error, then I’m guessing I have to re-define `Base.display_error`?

At any rate, it wouldn’t be done by default in my package, it would be an option that users have to explicitly activate and I will warn them that it’s a hacky solution.

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [February 28, 2022, 3:22pm UTC](https://discourse.julialang.org/t/intercepting-error-messages-how/77189/4 "2022-02-28T15:22:33Z")

</div>

> [@FedeClaudi](#):
>
> But is there an alternative to it like python’s exception hook?

There is `Base.Experimental.register_error_hint`, but you seem to already have discovered that. Your projects looks very exciting, so if you have a concrete proposal for what kind of hooks you would need, I think the core devs would be open to discuss potential changes to base.

> [@FedeClaudi](#):
>
> If lines like `Base.invokelatest(Base.display_error, errio, val)` that you’ve send above (and similar ones e.g. in VSCode’s Julia Extension) are what prints out the error, then I’m guessing I have to re-define `Base.display_error` ?

`display_error` should end up calling `showerror`, so redefining that should have similar effects.

---

<div class="post-metadata">

**Author:** ![FedeClaudi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fedeclaudi/32/33490_2.png) [@FedeClaudi](https://discourse.julialang.org/u/FedeClaudi)\
**Post date:** [February 28, 2022, 3:27pm UTC](https://discourse.julialang.org/t/intercepting-error-messages-how/77189/5 "2022-02-28T15:27:11Z")

</div>

Thanks!

I will try starting a discussion with the Julia devs, and perhaps use the hacky fix in the meanwhile.

> `display_error` should end up calling `showerror` , so redefining that should have similar effects.

Correct, for now I have re-defined `display_error` and `show_backtrace` and seems to get me most of the way there.

I’ve also seen [redirect\_stderr](https://docs.julialang.org/en/v1/base/io-network/#Base.redirect_stderr), but I’m not sure if/how I could use that to achieve my goal here.

Either way, this was very helpful thank you for your time!

---

<div class="post-metadata">

**Author:** ![FedeClaudi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fedeclaudi/32/33490_2.png) [@FedeClaudi](https://discourse.julialang.org/u/FedeClaudi)\
**Post date:** [March 4, 2022, 1:30pm UTC](https://discourse.julialang.org/t/intercepting-error-messages-how/77189/6 "2022-03-04T13:30:29Z")

</div>

@simeonschaub I just wanted to thank you again.  
The error formatting is coming along fairly well!

 ![image](https://global.discourse-cdn.com/julialang/original/3X/1/b/1befb1194654b3f67e638ec66059b7c7bd7d9bf0.png)

---

<div class="post-metadata">

**Author:** ![fredrikekre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fredrikekre/32/1688_2.png) [@fredrikekre](https://discourse.julialang.org/u/fredrikekre)\
**Post date:** [March 7, 2022, 11:24am UTC](https://discourse.julialang.org/t/intercepting-error-messages-how/77189/7 "2022-03-07T11:24:25Z")

</div>

Perhaps a solution would be to push your own display to the top of the display stack. [Literate.jl](https://github.com/fredrikekre/Literate.jl) uses [`pushdisplay`](https://github.com/fredrikekre/Literate.jl/blob/9d96d4e8c7cb329453fcf46bdd5b4ec64db7ab12/src/Literate.jl#L810) and [`popdisplay`](https://github.com/fredrikekre/Literate.jl/blob/9d96d4e8c7cb329453fcf46bdd5b4ec64db7ab12/src/Literate.jl#L820) to catch display calls. I believe something similar is done for e.g. the plot pane in the VS code extensions.

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [March 7, 2022, 11:27am UTC](https://discourse.julialang.org/t/intercepting-error-messages-how/77189/8 "2022-03-07T11:27:18Z")

</div>

Any chance that these pretty stack traces will become the default REPL experience? 😍

---

<div class="post-metadata">

**Author:** ![FedeClaudi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fedeclaudi/32/33490_2.png) [@FedeClaudi](https://discourse.julialang.org/u/FedeClaudi)\
**Post date:** [March 7, 2022, 11:33am UTC](https://discourse.julialang.org/t/intercepting-error-messages-how/77189/9 "2022-03-07T11:33:24Z")

</div>

Thanks @fredrikekre I’ll look into that.

@juliohm that seems unlikely (for now at least). But using term is just a couple lines of code to set them up!

---

<div class="post-metadata">

**Author:** ![FedeClaudi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fedeclaudi/32/33490_2.png) [@FedeClaudi](https://discourse.julialang.org/u/FedeClaudi)\
**Post date:** [March 7, 2022, 4:50pm UTC](https://discourse.julialang.org/t/intercepting-error-messages-how/77189/10 "2022-03-07T16:50:15Z")

</div>

@friederikemeier

`AbstractDisplay` is something that I didn’t know about, and it might be very useful in the future, but as far as I can tell I can’t make much use of it here. Thanks anyway!

---

<div class="post-metadata">

**Author:** ![Jollywatt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jollywatt/32/202198_2.png) [@Jollywatt](https://discourse.julialang.org/u/Jollywatt)\
**Post date:** [August 18, 2022, 12:24am UTC](https://discourse.julialang.org/t/intercepting-error-messages-how/77189/11 "2022-08-18T00:24:55Z")

</div>

This is an exciting project to see being worked on!

IMO, one of the main disadvantages of Julia in terms of user experience, apart form [TTFX](https://discourse.julialang.org/t/taking-ttfx-seriously-can-we-make-common-packages-faster-to-load-and-use/74949), is that **error messages are often verbose and intimidating**.

It is not uncommon to receive three-page nested error messages when (ab)using `DataFrames.jl`, for example, and I think this is a significant problem for Julia’s general adoption. Especially for those coming from languages like Python, whose traceback messages are (mostly) very succinct and lucid, such long error messages can be scary and hard to glean information from.

I don’t think it’s appropriate for `Term.jl`’s style of displaying error messages to become Julia’s default, but I would love to see Julia’s error messages become something in between what they are now and the proof-of-concept shown in this post.

* * *

> [@FedeClaudi](#):
>
> I will try starting a discussion with the Julia devs, and perhaps use the hacky fix in the meanwhile.

I hope the Julia devs agree that providing an interface for intercepting and display error messages is a good investment. I’m thinking this might also be a boon for HTML-based front-ends like [`Pluto.jl`](https://github.com/fonsp/Pluto.jl).

---

<div class="post-metadata">

**Author:** ![nilshg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilshg/32/2283_2.png) [@nilshg](https://discourse.julialang.org/u/nilshg)\
**Post date:** [August 18, 2022, 5:03am UTC](https://discourse.julialang.org/t/intercepting-error-messages-how/77189/12 "2022-08-18T05:03:29Z")

</div>

One thing that might help with this in the near future is to replace the parser with JuliaSyntax, which is now possible thanks to

> <https://github.com/JuliaLang/julia/pull/46372>
>
> This enables the use of JuliaSyntax.jl as the Julia parser for the runtime, whic…h greatly improves parser error messages in various cases. As an experimental feature, this is only enabled if the \`JULIA\_USE\_NEW\_PARSER=true\` environment variable is set.
> 
> !\[20220817\_17h14m06s\_grim\](https://user-images.githubusercontent.com/601473/185057712-31deb848-e545-4f03-8fe7-fbb2462f9ae4.png)
> 
> For now I've installed it after bootstrapping because this is the simplest (flisp parser still used for bootstrap). In the future we can solve bootstrapping but this isn't necessary right away.
> 
> 
> \## API Versioning: Stdlib woes vs vendoring
> 
> The simplest way to get this working immediately was as a stdlib. However in retrospect this has several downsides:
> \* As only version JuliaSyntax-0.1, the \`JuliaSyntax\` API is not at all stable. The only stable API for using this from \` Base\` should be \`Meta.parse()\` and \`Expr\`. Therefore, I think users should not really be able to do \`using JuliaSyntax\` and get the version bundled with Base.
> \* For use in tooling like the language server, it's necessary for the JuliaSyntax API (custom syntax tree types etc) to be able to evolve with its own versioning scheme independent from whatever version of \`Base\` someone is using. Users should be able to install a "normal" version of \`JuliaSyntax\` via \`Pkg\`.
> 
> So I think having this as a stdlib doesn't really make sense and we are left with some kind of vendoring approach. I think what I'll try next is to include the parser at the end of building \`Base\`.
> 
> Having said all that, it should be easy to try this out already :-)
