Skip to main content

Error handling

This section explains how Stan stores and handles data, and the implications of these design decisions on error handling.

Good ol' try-catch

One of the major differences between Stan and libraries like Recoil or Jotai is its approach to Suspense. While Stan is still Suspense-enabled (see the react-suspense example), it is framework-agnostic and does not assume it's running in a React context (no pun intended). In particular, this means that get calls (when accessing a selector's dependencies) won't throw, allowing for more natural and idiomatic error handling:

declare const dep: Scoped<ReadonlyState<Promise<number>>>;

const mySelector = selector(async ({ get }) => {
try {
const result = await get(dep); // This will only throw on an actual error

return result;
} catch {
return 'nope';
}
}); // Scoped<ReadonlyState<Promise<number | "nope">>>

Async errors

Stan does not implement any internal abstraction around state values. Everything is stored as-is and receives no special treatment, with one small exception: rejected Promises.

When a Stan state satisfies the Scoped<ReadonlyState<PromiseLike<any>>> constraint - or, in simpler terms, when a selector returns something that looks like a Promise - and that Promise is rejected, Stan won't cache it. This means the state will be re-evaluated the next time it's accessed. This behavior is best illustrated by the error-handling example.