[API reference](https://evolu.dev/docs/api-reference) › [@evolu/web](https://evolu.dev/docs/api-reference/web) › addUncaughtErrorListener

```ts
function addUncaughtErrorListener(
  scope: EventTarget,
  listener: (error: Error) => void,
): Disposable;
```

Defined in: [packages/web/src/Worker.ts:331](https://github.com/evoluhq/evolu/blob/aa223771feea747ffb1b0f5f3271574455633e37/packages/web/src/Worker.ts#L331)

Passes each uncaught error and unhandled rejection of a worker global scope
to `listener` as an `Error` from [defectToError](https://evolu.dev/docs/api-reference/common/Error/functions/defectToError).

Browsers never pass a shared worker's uncaught errors to a page's error
handlers, and no worker passes its unhandled rejections to its page. A shared
worker calls this with its global scope, `self`, to send them to its pages,
for example over a BroadcastChannel. Defects of a Run from [createRun](https://evolu.dev/docs/api-reference/web/functions/createRun)
arrive too, because it reports them with `reportError`, which dispatches
"error" on the global scope.

The events stay uncanceled, so the browser still logs them, and a dedicated
worker still passes its uncaught errors to its page. The listeners stay until
disposal, so they also receive errors after a Run's panic.

### Example

```ts
import { assertEqual } from "@evolu/common";
import { addUncaughtErrorListener } from "@evolu/web";

const messages: Array<string> = [];
// A worker passes its global scope, `self`.
const scope = new EventTarget();
using _listener = addUncaughtErrorListener(scope, (error) => {
  messages.push(error.message);
});

scope.dispatchEvent(
  Object.assign(new Event("error"), { error: new Error("unexpected") }),
);
assertEqual(messages, ["unexpected"]);
```