useOnRpcError
One place to react to rpc failures that are nobody's local problem — auth loss, telemetry, toasts.
Some failures do not belong to the component that triggered them. An
Unauthenticated error means the session is gone, whatever screen you happen to
be on. Rather than repeat that check in every useMutation call site, each api's
runtime carries an error bus; this hook subscribes to it with React lifecycle.
import { useOnRpcError } from '@voltro/client'
import { errorTag } from '@voltro/protocol'
useOnRpcError('app', useCallback((e) => {
if (errorTag(e.error) === 'Unauthenticated') redirectToSignIn()
}, []))The event is { source, tag, error, traceId? }. source is
'mutation' | 'action' | 'subscription', so both unary calls and stream
failures arrive here. error is the raw value — a Schema.TaggedError, a plain
Error, or anything else that was thrown; errorTag(err) reads _tag off
tagged errors and returns undefined otherwise. traceId is the same id the
server logged, so a handler can point at voltro logs --trace <id>.
Two things to know. The hook re-subscribes whenever the listener reference
changes, so define it with useCallback or at module scope unless you want that.
And the bus is per api runtime — an app talking to several apis subscribes once
per api name.
You do not need this hook to REPORT rpc failures. Every event this bus emits
is also published on the client error bus, so a reporter — the Sentry browser
integration, or anything wired with subscribeClientErrors — already sees it,
under source: 'rpc.mutation' | 'rpc.action' | 'rpc.subscription' with the rpc
tag and traceId in context. This hook is for cross-cutting policy (redirect
on Unauthenticated, toast on a network failure), not for telemetry; bridging
the two by hand now reports twice.
Everything is published, including a reconnect storm. If that is too loud for your reporter, gate it in the subscriber — which failures are worth an event is your policy, and the bus cannot hold one for every subscriber.
This is the read side of failures that already happened on the wire. To push a
client-side error the server never saw, call reportClientError(error, context)
instead. Note also that a subscription failure after data arrived reaches only
this bus, never the hook's error field — see
Queries.