API reference › @evolu/common › local‑first/Evolu › EvoluErrorDep

Defined in: packages/common/src/local-first/Evolu.ts:1061

Dependency wrapper for the shared EvoluError store.

Properties

evoluError

readonly evoluError: ReadonlyStore<
  | EvoluError
| null>;

Defined in: packages/common/src/local-first/Evolu.ts:1144

ReadonlyStore of EvoluError shared by all Evolu instances created from the same createEvoluDeps result.

Starts at null and otherwise holds the latest reported error until the first UnsupportedDbVersionError. That refusal remains for the lifetime of these dependencies, even if a tenant is disposed and recreated. Later errors are still logged but do not replace it or notify this store's subscribers. Fresh dependencies start with a fresh error store. An OtherBuildRunningError reports a wait, so the store returns to null when the wait ends, unless another error replaced it.

Subscribe once to show user-facing error messages across all instances. A database whose worker throws while it starts or handles a request, or whose worker script fails to load on the web, is refused with an UnknownError. While a refused database's tenant remains alive, the SharedWorker sends the refusal to each tab once, including tabs that connect later, and starts no replacement database workers. After all instances release that tenant and it is disposed when idle, creating another instance retries startup and may send the refusal again. On the web, a tab refused with UnsupportedDbVersionError first reloads once instead. Show that blocking message outside any query-loading boundary, so pending queries do not hide it.

An UnknownError leaves Evolu in an unknown state, so the app can only ask the user to close all its tabs. A failed shared worker closes itself, and a database whose worker failed stays refused while any tab uses it, so the app opened again starts over. Some errors reach every tab, such as an unexpected failure of the shared worker. An app that forwards this store to an error tracker from each tab then reports such an error once per tab. A failed worker that a tab hosts, except a web worker whose script failed to load, is also reported by that tab's error reporter, its error handlers on the web or ErrorUtils in React Native, so an app that sends both to one error tracker sees that failure twice. A tab hosts each database's worker, and also the shared worker in React Native or in a browser without SharedWorker.

Example

import { assertEqual, createStore, type EvoluError } from "@evolu/common";
import type { EvoluErrorDep } from "@evolu/common/local-first";

// The message for the current error, or null for none.
const errorMessage = (error: EvoluError | null): string | null => {
  if (!error) return null;
  switch (error.type) {
    case "UnsupportedDbVersionError":
      return "Your data requires a newer version of this app. Please update it.";
    case "DatabaseHeldError":
      return "Your data is still in use elsewhere. Close this app's other tabs or restart the browser, then reload this page.";
    case "OtherBuildRunningError":
      return "This app is open in another tab with a different version. Close that tab to continue.";
    case "UnknownError":
      return "Something went wrong. Please close all tabs of this app and open it again.";
  }
};

// Stand-in for run.deps.evoluError from createEvoluDeps.
using evoluError = createStore<EvoluError | null>(null);
const deps = { evoluError } satisfies EvoluErrorDep;
// What the app showed over time; null hides the message.
const shown: Array<string | null> = [];

deps.evoluError.subscribe(() => {
  shown.push(errorMessage(deps.evoluError.get()));
});

// Another version keeps this tab waiting, then the wait ends.
deps.evoluError.set({ type: "OtherBuildRunningError" });
deps.evoluError.set(null);

assertEqual(shown, [
  "This app is open in another tab with a different version. Close that tab to continue.",
  null,
]);