Lwt exception backtrace lost with let* and let+

I have been using Lwt’s Syntax extensions: let* and let+ for awhile, but now I noticed that thrown exceptions lose valuable information compared to let%lwt.

For example with code using let* () = ... I get (which isn’t very useful):

ASSERT err
FAIL err
Raised at file "src/alcotest-engine/test.ml", line 143, characters 20-48
Called from file "src/core/lwt.ml", line 1864, characters 23-26

but with let%lwt () = ... I get:

ASSERT err
FAIL err
Raised at file "src/alcotest-engine/test.ml", line 143, characters 20-48
Called from file "src/core/lwt.ml", line 1927, characters 23-26
Re-raised at file "src/my_tests/my_tests.ml", line 41, characters 16-129

it shows exactly where it failed.

How can I fix this, so that the syntax extensions also include where the exception was thrown?

That is a known problem, let* is exactly like calling Lwt.bind which looses the trace, let%lwt is actually using Lwt.backtrace_bind IIRC

1 Like

thanks Eduardo, are you aware of any fixes / workarounds and etc.? like using the ppx at some points and etc.?

(I find let* to be more readable and closer to the syntax found in other languages)

Here’s what the ppx generates:

I don’t think you’ll able to replicate that with a (let*) because the backtrace would point at the point of definition of (let*), and not at the call site.

You can figure out the call site location by walking up the call stack (see this code which does exactly that). So you could track the location of every bind. However you couldn’t inject such a location in a regular backtrace, so the backtrace would have to be manually maintained by the Lwt module.

1 Like

Well with typpx or something like that, it should be possible

For some errors, it might make sense to include the location of the call site in the error payload. This is similar to how the Assert_failure includes location information in its constructor parameters.

It’s not an ideal solution because you might accidentally bubble up location information into error messages seen by user. But if you are careful you can strip that when you pretty-print the errors in production mode. It’s also less than ideal because you’re shouldering the burden of location tracking yourself.