Skip to content

Error handling behavior

Ignoring specific errors

Not every thrown error is a bug worth showing a fallback for — the classic case is a cancelled fetch, whose AbortError is expected and shouldn't be treated as a component crash. Both <ErrorBoundary> and useGlobalErrorCapture() accept a shouldCatch predicate for this: return false and the error passes through completely untouched — no state change, no error event, no report, no fallback.

vue
<ErrorBoundary :should-catch="(e) => e.error?.name !== 'AbortError'">
  <UserProfile :id="userId" />
</ErrorBoundary>

For <ErrorBoundary>, a rejected predicate doesn't just no-op locally — the error continues through Vue's own onErrorCaptured propagation, so an ancestor boundary (or the app-level error handler) still gets a chance to see it, exactly as if this boundary weren't in the tree at all. This is different from the isolate: false bubbling described below, which is this package's own explicit channel for errors it did handle locally.

useErrorBoundary() doesn't take a shouldCatch — since captureError() is called explicitly by your own code, you already control whether to call it.

Nested boundaries

By default (isolate: true) an error is fully absorbed by the nearest <ErrorBoundary> — it does not propagate further, matching Vue's own onErrorCaptured semantics for a handled error.

With isolate: false, after handling the error locally the boundary also pushes it to the nearest ancestor <ErrorBoundary> through an internal provide/inject channel (not through Vue's own onErrorCaptured bubbling, which this package deliberately blocks at each level so it can render its own fallback). The ancestor's error event fires, its own state updates, and it becomes visible if the ancestor's own fallback would replace the affected content.

A reporter attached to any boundary in the chain is guaranteed to be called exactly once per error, even if both the child and the ancestor have reporters configured — the first boundary to actually report it "claims" it, and later boundaries in the chain skip re-reporting the same error instance.

What errorCaptured does and doesn't catch

Vue's onErrorCaptured (and therefore <ErrorBoundary>) does catch:

  • Synchronous errors in a descendant's render function or setup().
  • Errors in an async setup() after an await (with or without <Suspense>).
  • Errors thrown from Vue-compiled v-on handlers — both @click="mayThrow" on native elements and handlers for component-emitted events.
  • Watcher callbacks, directive hooks, transition hooks.

It genuinely does not catch:

  • Errors in a raw addEventListener callback that bypasses Vue's event binding.
  • Errors in setTimeout/Promise chains unrelated to a component's own async setup().
  • Unhandled promise rejections.
  • Errors thrown inside your own errorCaptured handler or reporter — this package guards against that recursion internally (a throwing onError/reporter is caught and logged, never re-enters boundary state).
  • An error already handled by a descendant boundary with isolate: false being reported a second time — see the dedup guarantee above.

Use useErrorBoundary().captureError() or useGlobalErrorCapture() for the first three.