Discussions on ReScript exception encoding

I don’t understand this question… how am i supposed to know if the new implementation will work with the tooling i use(or their internal tooling) without trying it in prod?

I just want to stress how frustrating it was to debug this issue previously and how i wish to not ever do this again:
Since it broke the standard Bugsnag was relying on, it took me 2 days of real bugs in production!! to figure out ReScript was doing something weird(i was suspecting Bugsnag at first, because who will encode an exception differently, i thought to myself).i would imagine anyone less committed to rescript to just drop it and move on.

If one of the premises of ReScript is to produce a SANE Js -> proposal 1 is a no-go. - lets be true to our marketing.

1 Like

Yeah. I agree. Exceptions is a surface area with the outside world (JS). So it would be nice to have proper JS-conform exceptions. I think solution 1 is a small step in the right direction, but something like solution 2 which might be harder to implement in a clean way is probably something that should be on the longer term roadmap to make it fit in better with the JS ecosystem. If the implementation of 1 does not help us to eventually get to 2, I think effort is probably spent better on 2 in the longer term.

3 Likes

Any update regarding this?
I would say this is probably the most painful point for us using rescript in the real world(to the point that i’ve not idea how other people are doing this… - happy to learn)
We’re using Sentry to capture FE exceptions(used to use bugsnag where it also didnt work).

All our exception look like:

Error: Non-Error exception captured with keys: Error, RE_EXN_ID

Which, compounded with the fact that rescript doesnt have sourcemaps, and that webpack/react makes the trace impossible to read - makes us ignore production exceptions, which is just terrible for a language that one of the selling point is Stability on production…

4 Likes

Hi, we share the pain, we may consider doing some incremental improvement soon

2 Likes

In the server apps, we translate on the Rescript/JavaScript boundary.

Also, errors in Rescript are not signalled by exceptions only, they can be returned as result<'a,'e>. So just a better encoding might not solve the whole problem for us.

1 Like

How about something like this?

// Helper to throw JavaScript Error
@new external error: string => exn = "Error"
let throw = exn => exn->Printexc.to_string->error->raise

// Suppose this is your app entrypoint
let main = () => assert(false)

// Top-level exn-to-Error converter
let () = try main() catch {
  | exn => throw(exn)
}
1 Like

This look like the most practical in terms of DX, if we (for instance) look at the output in Safari dev tools.

3 Likes

So, this topic is dead. yet we’re now facing the same issue with yet another industry standard tool - DataDog.

Specifically we get the following message from them:
" ERROR STACK

No stack, consider using an instance of Error

"

@Hongbo - or anyone from the ReScript team - how is this not a priority for allowing us running Safely in production?

1 Like

I think it is an important issue to be addressed. We are a small team, and none of us work on it full time, so I guess you need be a little patient

Have you considered wrapping the window.onerror property after your analytics error collectors are installed?

// install rescript error shim first
window.addEventListener("error", function rescriptPriorityHandler(event) {
  if (Object.prototype.hasOwnProperty.call(event.error, "RE_EXN_ID")) {
    event.preventDefault();
    event.stopPropagation();
    event.error.Error.message = event.error.RE_EXN_ID;
    throw event.error.Error;
  }
});

// analytics error handlers
const originalOnError = (window.onerror = function analyticsonerror(
  message,
  source,
  lineno,
  colno,
  error
) {
  console.log("Original error handler called!");
});

window.onerror = function rescriptErrorWrapper(
  message,
  source,
  lineno,
  colno,
  error
) {
  if (Object.prototype.hasOwnProperty.call(error, "RE_EXN_ID")) {
    return true;
  } else if (typeof originalOnError === "function") {
    originalOnError.apply(this, arguments);
  }
};
2 Likes

The challenges is that a niche language feature-- extensible variants shared the same encoding with exceptions, so it is hard to change the encoding of exception without touching the extensible variants, unless we remove that niche feature…

We use some tools (like Graphile-Worker) that are based on catching exceptions that must be JS Errors, having Rescript exceptions encoded as JS Errors would make integration much easier.

We could make a poll, but I would personally easily trend easier JS interop with dropping support for extensible variants, I suspect very few people actually use them.

3 Likes

My bad actually, Graphile-Worker doesn’t expect errors to be instance of JS Error, it just expects message and stack fields, so for this tool your proposal #1 would be enough given we can add an inline record with a message field inside the rescript exception and that it would add the stack.

Another improvement would be to encode the first element of the payload when it’s a string as message instead of _1, that would allow for a much better JS integration for default exceptions, like Failure(string) (failwith), Invalid_args, etc and for exceptions that have only one string argument and where you don’t want to add the overhead of a adding an inline record with a message field.

@Hongbo any update regarding this? we still have production exceptions and no way to monitor them

Hi I am on a parental leave, will have a look later

8 Likes