The basic syntax for invoking a child machine is the same as for invoking promises or any other service:
// ...
current_state: {
invoke: {
src: childMachine,
data: {}, // optional initial context
onDone: {
target: 'next_state',
actions: 'someAction',
},
onError: {
target: 'error',
actions: 'printError',
}
},
},
When you invoke a promise, an error thrown inside will automatically trigger the onError block. You could expect the same thing to happen when invoking a child machine and throw an error like so:
// ...
states: {
fetch: {
invoke: {
src: 'fetchSomething',
onDone: { target: 'upsert', actions: 'someAction' },
onError: {
actions: (_, event) => {
throw event.data
},
},
},
},
upsert: {
// ...
},
success: {
type: 'final',
},
},
The problem
However, this doesnât work, and the âInvoking servicesâ docs only mention sendParent as a way to communicate from child to parent machine.
You could use sendParent to solve the issue, but youâd need to send a custom event from your child machine and handle it in the parent, outside of the onError block:
// ... child machine
actions: {
throwError: sendParent((_, event) => ({
type: 'CHILD_ERROR',
data: event.data,
})),
},
// ... parent machine
current_state: {
invoke: {
src: childMachine,
data: { /* ... */ },
onDone: { /* ... */ },
},
on: {
CHILD_ERROR: {
target: 'error',
actions: 'printError',
},
},
},
Thatâs actually what I did until a friendly discord user pointed me in the right direction.
The solution
Turns out the answer was in the âActionsâ page of the docs, under the escalate action, which âescalates an error by sending it to the parent machine.â Exactly what we need.
Hereâs how youâd refactor the throwError action so that it would trigger the onError block of the parent:
// ...
throwError: escalate((_, event) => ({
data: event.data,
})),