Skip to main content

Error Handling

Handling errors in specific saga​

You can use classic try..catch in sagas:

const watcher = createSaga(async function() {
try {
await this.call(worker, 'test');
} catch (err) {
console.error(err.message); // test error
}
});

const worker = createSaga(async function(text: string) {
throw Error('test error');
console.log(text);
});

But here comes a possible inconvenience. Cancellation is done by throwing an error (specifically, an AbortError), and it can be performed manually (via cancel effect calls) and automatically (useSaga calls cancel on React component unmount as well). This type of error can be refined with isAbortError helper like shown below:

import {isAbortError} from '@promise-saga/core';

export const saga = createSaga(async function () {
try {
await this.call(inner);
} catch (err) {
if (!isAbortError(err)) { // refine the Aborted error manually
// handle error
}
}
});

Logging all saga errors​

You can specify the createCreateSaga onError handler, but note the following about this handler:

  • It runs in parallel with the main saga error handling, meaning it does not prevent you from refining an error, as shown in the previous section.
  • It triggers every time any saga at any level throws an error upward. Even if the error is caught at a higher level, this will not prevent the onError handler from being fired.
import {createCreateSaga} from '@promise-saga/core';

export const createSaga = createCreateSaga({
plugin,

onError(err, node) {
if (node.level === 1 && isSagaError(err)) {
console.error(err.node, node);
}
},
});

In the example above, we want to log only top-level errors (node.level = 1), which are not handled by any sagas at other levels.

Every error occurring within a saga has a node property of type SagaTreeNode. Additionally, the node is passed into the handler function immediately after the error object. These nodes might be identical, but not always.

For instance, if an error occurs at level 2 (SagaA calls SagaB, and SagaB throws an error), err.node.level will equal 2. However, the error handler in the example above is designed to log uncaught errors only at node.level = 1. In this case, the error bubbles up similarly to an event in a browser, so err.node.level is comparable to Event.target, where node represents the node where the error occurred, and node.level is comparable to Event.currentTarget, where node is the node listening for the errors.

Check error handling within non-blocking calls for more information.