Ask
174
@epsilon_eddie ·

Errors thrown in a server action come back as a digest string in production and I cannot see what happened

In development I get a real stack trace, in production the client just gets a generic message and a digest number, so I am debugging by guesswork. There is a mix of expected failures like a duplicate email and genuinely unexpected ones like the database being unreachable, and right now both look identical to the user. What is the pattern people settled on for the two cases.

8 answers Share
Report

Answering anonymously — a moderator will review it first.

  • @adjunct_life · last mo.

    Partly disagreeing with returning errors as values everywhere. Once every action returns a union of success and six kinds of failure, every call site grows a switch, and in a large app that becomes more code than the features. I keep returned errors strictly for field level validation that the form renders, and let everything else throw into a boundary with a sensible fallback. Fewer paths, less ceremony, and the unexpected cases end up somewhere a human actually looks.

    154
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @listener_lena · last mo. · 3 replies

    The redaction is deliberate, because anything thrown on the server could contain connection strings or user data, so the framework replaces it with a generic message plus a digest and logs the real error server side keyed to that digest. So the first fix is not in your code, it is making sure you can find the digest in your logs, and the hook for that is onRequestError in instrumentation, which is where you forward to whatever error reporter you use. Once a digest maps to a stack trace in your reporter, production stops being guesswork.

    218
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
    • @epsilon_eddie · last mo.

      I did not know instrumentation had a request error hook. That alone changes how bad this is.

      64
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report
    • @streak_sol · last mo.

      Wire it up before you refactor the action code, otherwise you are changing error handling while blind.

      47
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report
  • @orm_tamsin · last mo.

    For the two categories, the split that has worked for us is: expected and user actionable failures are values, unexpected failures are exceptions. Duplicate email returns an object with a field level message that the form renders through the action state, and the database being down throws and is caught by an error boundary that shows a try again screen. The rule of thumb is whether the user can do something about it, because if they can, it is part of your data model, and if they cannot, it belongs to the boundary.

    189
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @semver_sid · last mo.

    Log the digest, return validation errors as state, throw the rest, and never catch around a redirect. That is the whole pattern.

    128
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @handy_orla · last mo. · 2 replies

    The gotcha that cost me an afternoon: redirect and notFound work by throwing a special error internally, so if you wrap your whole action body in a try catch, your catch swallows the redirect and it silently stops working. Either put the redirect after the try catch block or rethrow anything that is not yours. It looks exactly like a routing bug and it is not.

    176
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
    • @epsilon_eddie · last mo.

      This is happening in one of my actions right now and I had blamed the router. Thank you.

      58
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report