1

Is it possible to catch an exception in a guard?

For example:

const { interpret, createMachine } = require("xstate");

const fetchMachine = createMachine(
  {
    initial: "start",
    states: {
      start: {
        on: {
          LETS_TRY: "subService",
        },
      },
      subService: {
        invoke: {
          src: () => Promise.resolve(),
          onDone: [
            {
              target: "stop",
              cond: "someGuard",
            },
          ],
          onError: "stop",
        },
      },
      stop: {
        type: "final",
      },
    },
  },
  {
    guards: {
      someGuard: () => {
        throw new Error("error in guard");
      },
    },
  }
);

try {
  interpret(fetchMachine)
    .start()
    .send("LETS_TRY");
} catch (e) {
  console.log("exception caught", e.message);
}

The expected output of this code is "exception caught" but instead I am getting the following error message:

Error: Unable to evaluate guard 'someGuard' in transition for event 'done.invoke.(machine).subService:invocation[0]' in state node '(machine).subService'

Example is available also on codesandbox.

1 Answers1

0

No, guards return only true or false and serve as a condition to determine whether a transition should happen.

https://xstate.js.org/docs/guides/guards.html#guards-condition-functions

If you want to throw an explicit error, you can try with an action:

onDone: [
  {
    target: "stop",
    actions: () => {
      throw new Error("error in guard");
    },
  },
]

Or if you want to read the error that is thrown from the promise, you can check the event object from the onError state.

onError: {
  target: "stop",
  actions: (context, event) => {
    console.log(event.data);
  },
}
z_lander
  • 104
  • 1
  • 8
  • I don't want to make a mistake on purpose, but an error can happen anywhere in the code, including guards. It seems that I cannot catch it when it is thrown in a guard. – Alexander Chirkov Jun 22 '23 at 15:01
  • I've got your concern now. Never tried it on production, but I guess you can try something in this manner https://codesandbox.io/p/sandbox/distracted-water-5659ct?file=%2Findex.js%3A23%2C9 – z_lander Jun 22 '23 at 15:29