Open boneskull opened 4 weeks ago
I updated the title to better describe what I think is happening; my hunch is that it can be fixed in the toPromise
implementation.
It may be worth mentioning why the context
assignment function would ever want to throw. Because:
const machine = setup({
types: {
input: {} as {signal: AbortSignal}
}
}).createMachine({
context: ({input: {signal}}) => {
if (signal.aborted) {
throw new AbortError(signal.reason);
}
}
});
I updated the title to better describe what I think is happening; my hunch is that it can be fixed in the toPromise implementation.
It can't be fixed there. This error is thrown synchronously. By the time toPromise
gets actually called in this example... it's already too late.
You can (likely) work around this problem like this:
const actor = createActor(TestMachine);
const p = toPromise(actor);
actor.start();
await p;
@Andarist Not sure I love it, but I can confirm that workaround works: https://stackblitz.com/edit/github-trfney-kh9qur?file=src%2Fmain.ts
Might want to update the docs and/or add a warning about this if you don't plan to address it otherwise 😄
To be clear, I don't necessarily say I love it either 😉
XState version
XState version 5
Description
Given:
error
subscriber is registered with Acontext
assignment function throws an error EE cannot be caught by any mechanism other than a global error listener (e.g.,
window.onerror
orprocess.on('uncaughtException')
.Even if a machine actor is wrapped in
toPromise()
, E is still thrown this way in addition to being rejected out of thePromise
.This behavior does not occur if the machine actor has a subscriber with an
error
listener.I really don't want to create a bunch of subscriptions where
toPromise()
would work for my purposes. 😄Expected result
The error thrown by the
context
initializer should not be thrown in addition to being rejected.Actual result
The "extra" error thrown is only catchable via a global error handler.
Reproduction
https://stackblitz.com/edit/github-trfney?file=src%2Fmain.ts
Additional context
This may be expected behavior. I understand that an actor that is started without an
error
listener and isn't wrapped in aPromise
has no other choice but to throw an error this way; there's nowhere for it to go.In Node.js, an EE will emit an
error
event, which can be listened to. If it is listened to, then the EE won't throw an uncaught exception. However, theonce
wrapper (which is only vaguely analogous totoPromise()
) will also avoid the uncaught exception:That's why I think this is a bug. Like above,
toPromise
should act like a subscriber with anerror
listener.It may also not be unique to the
context
assignment function, either...