In the following situation:
#-------------------------------------
module Internal
struct WrongInput <: Exception end
f(_) = throw(WrongInput())
f(x::Int) = x
g(x) = f(x)
h(x) = g(x)
export h
end
#-------------------------------------
module Exposed
using ..Internal
struct NiceReport <: Exception end
p(x) = h(x)
q(x) = p(x)
welcome(x) =
try
q(x)
catch e
e isa Internal.WrongInput && rethrow(NiceReport())
rethrow(e)
end
export welcome
Base.showerror(io::IO, ::NiceReport) =
print(io, "Don't worry it's not that bad just try again <3")
end
#-------------------------------------
# User.
using .Exposed
my_u(x) = welcome(x)
my_v(x) = my_u(x)
my_w(x) = my_v(x)
my_w("hi")
User obtains the following stacktrace:
ERROR: LoadError: Don't worry it's not that bad just try again <3
Stacktrace:
[1] f(::String) <<
@ Main.Internal ./test.jl.jl:4 <<
[2] g(x::String) <<
@ Main.Internal ./test.jl.jl:6 <<
[3] h(x::String) <<
@ Main.Internal ./test.jl.jl:7 << Garbage (from user POV).
[4] p(x::String) << Useless for debugging: not a bug (in the lib).
@ Main.Exposed ./test.jl.jl:17 <<
[5] q(x::String) <<
@ Main.Exposed ./test.jl.jl:18 <<
[6] welcome(x::String) <<
@ Main.Exposed ./test.jl.jl:21 <<
[7] my_u(x::String) <<
@ Main ./test.jl.jl:37 <<
[8] my_v(x::String) <<
@ Main ./test.jl.jl:38 << *USEFUL* (from user POV).
[9] my_w(x::String) <<
@ Main ./test.jl.jl:39 <<
[10] top-level scope <<
@ ./test.jl.jl:41 <<
[11] top-level scope <<
@ REPL[1]:1 <<
in expression starting at ./test.jl:41
Is there a way I could reliably trim frames [1] to [6] so as not to bury them into the lib implementation detail? The relevant info for them only starts on frame [7], and the deepest the lib the further up they need to scroll so as to just read the report.
Using throw(NiceReport()) instead of rethrow(NiceReport()) does cut it exactly where it should, but then the caused by section still flushes the report up.
(currently investigating Base.current_exceptions)
(nah, it doesn't seem we can mutate the returned ExceptionStack, can we?)
I don't think so, but also, I think it's a bad idea to even try. A stack trace should contain the entire call stack so it's maximally usable for debuggning. Once you try messing with it to improve user friendliness, you should not be throwing un-caught exceptions, but instead print an error to stderr or something like that
Just printint to stderr would drop frames [7] to [11] which are useful to user IMO.
Also the purpose of rethrow(e) in case of unexpected exception is to really obtain the full stacktrace in case the lib itself needs debugging, so I wouldn't worry about this?
It's going to be difficult to determine beforehand what's useful to a user. What's to say the error isn't truly caused by something internal in your library?
When I say difficult, I mean that it's not possible at all. You can't have that information
This pattern does (IMO):
try
f()
catch e
e isa ExpectedExceptionType || rethrow(e) # Obtain full stracktrace for debugging.
# or handle e gracefully, forgetting about internal detail.
end
Ahh so you'd want something like Python's raise X from None. Yeah that makes sense
Don't know that one, but yeah why not :)
I wish to trim whichever part of the stack collected before the point I can assert that detail doesn't matter.
(and I take responsibility for this as the lib author ofc)
Ah yeah I see. I don't think that exists. But it would be nice to have
Siigh, should I request it you think or is there already relevant momentum in that direction?
I think Julia's errors have gotten very little attention in general
Alright. I'll report as a feat request unless someone else teaches us something about this today :)
(re)throw(e; afresh=true) or sth would be nice.
I'd really like a way to trim out noise from stacktraces too. The context I have this from is writing code like this:
macro outline(args...)
fargs = esc.(args[1:end-1])
body = args[end]
@gensym f
quote
$f($(fargs...),) = $body
@noinline $f($(fargs...),)
end
end
function my_sqrt(x)
if x < 0
@outline x throw(ArgumentError("my_sqrt does not take negative arguments, got $x"))
end
[...]
end
Here @outline automates the process of making a function barrier for me so that the error-path doesn't clog up the generated code for my_sqrt, which helps optimization, and then the value can be used in the error message without worrying about all the involved io/string operations.
But the downside is that it clogs up stacktraces with irrelevant information.
https://github.com/JuliaLang/julia/issues/62594.. let's see ¯\_(ツ)_/¯
Relevant: https://github.com/JuliaLang/julia/issues/40138
Hi. I am puzzled that #62606 is obtaining zero feedback. Do you think I did anything wrong? Is it unclear that I even expect anything? Should I just blame it on the northern hemisphere summer period and probable community exhaustion around v1.13 release?
I was thinking maybe I should just very briefly unmark the PR as a "draft" so as to trigger formal review requests? But maybe that'd be considered rude?
Or maybe this is just usual latency within the project?
Thank you, that is informative, although yet.. disheartening ^ ^"
I'm not sure how to best move forward then. I'll maybe start by un-drafting it to emit a more formal review request. But I'm unsure whether to spent more effort to get further on my own without getting at least a positive vibe/hint about the approach as a whole.. ?
Un-drafting is a good first step. To me, a draft PR means it's not ready for review yet.
I think it's a good idea to find some people who engaged in previous stacktrace discussions and ask them to review it. Probably people with merge rights are pressed for time in general and will be more likely to move forward with a PR if they can see that a few stakeholders agree this is the right direction
As someone who hasn't gone deep into the stacktrace discussion, it's this long long issue discussed over years, with lots of conflicting opinions. It takes a herculean amount of effort even to understand all the arguments from all sides, and that's before you even have the background knowledge to have an opinion about any given PR.
Thank you for feedback. I am at least aware of this attempt having been discussed in the past. And I figured that most of the discussion was whether we should accept a heuristic approach to pruning stacktraces (I would not fwiw). I understand how we may not succeed in converging towards a consensus there. The approach I offer is exact instead, the trick being to put lib authors in charge. Are you aware of other past attempts / different strategies?
it's a good idea to find some people who engaged in previous stacktrace discussions
Well there is at least @BioTurboNick but he seemed satisfied with the heuristic approach and, err.. maybe sour about the idea of trying this again ^ ^"
But do you happen to know more people like this? Or else how to search?
I’ve found that bots are very good at exploring issues and PRs and give a summary of the “prior art”.
I usually ask to gather a list of relevant issues/PRs with a quick summary on the topic of the discussion that I can then read on my own.
iago-lito said:
I am puzzled that #62606 is obtaining zero feedback
I agree with Jakob that the particular problem of stack frame hiding is a bit cursed, because the cost of getting it wrong (hiding a useful frame) is massive confusion, and the cost of leaving too many frames in is minor inconvenience. When you add the fact that the lower-complexity fewer-bugs option is just printing everything, you may understand the lack of motivation to hide frames. I can't express how much I appreciate your clear and well-written PR description, though.
whether we should accept a heuristic approach to pruning stacktraces (I would not fwiw).
We already have a few (kwcall, __repl_entry, possibly some in the backtrace machinery itself)
Last updated: Sep 19 2026 at 08:53 UTC