Errors

Server - LiveError

Throw LiveError from any live() function:

import { live, LiveError } from 'svelte-realtime/server';

export const deleteItem = live(async (ctx, id) => {
  if (!ctx.user) throw new LiveError('UNAUTHORIZED', 'Login required');

  const item = await db.items.get(id);
  if (!item) throw new LiveError('NOT_FOUND', 'Item not found');
  if (item.ownerId !== ctx.user.id) throw new LiveError('FORBIDDEN', 'Not yours');

  await db.items.delete(id);
});

Client - RpcError

On the client, server errors arrive as RpcError:

import { deleteItem } from '$live/items';

try {
  await deleteItem(id);
} catch (err) {
  err.code;    // 'UNAUTHORIZED', 'NOT_FOUND', 'FORBIDDEN', etc.
  err.message; // 'Login required'
}

Stream error states

Streams surface errors as { error } objects:

{#if $messages === undefined}
  <p>Loading...</p>
{:else if $messages?.error}
  <p>Error: {$messages.error.message}</p>
{:else}
  <!-- data -->
{/if}

Validation errors

live.validated() throws RpcError with code: 'VALIDATION' and an issues array:

try {
  await addTodo({ text: '' });
} catch (err) {
  err.code;   // 'VALIDATION'
  err.issues; // [{ path: ['text'], message: 'String must contain at least 1 character(s)' }]
}

Terminal close codes

When the WebSocket closes terminally (codes 1008, 4401, 4403, exhausted retries):

  • All pending RPCs reject with RpcError('CONNECTION_CLOSED')
  • All stream stores get { error } state
  • Offline queue is drained with errors

Error reporting hooks

onError

Both handleRpc and createMessage accept an onError callback for non-LiveError exceptions. LiveError throws are expected errors sent to the client; everything else is an unexpected failure that should be reported.

export const message = createMessage({
  onError(path, error, ctx) {
    sentry.captureException(error, {
      tags: { rpc: path },
      user: { id: ctx.user?.id }
    });
  }
});

The callback receives three arguments:

ArgumentDescription
pathThe RPC path that failed (e.g. chat/sendMessage)
errorThe raw error object
ctxThe request context (includes user, ws, etc.)

onCronError

For cron jobs, use the standalone onCronError function:

import { onCronError } from 'svelte-realtime/server';

onCronError((path, error) => {
  sentry.captureException(error, { tags: { cron: path } });
});

onCronError receives the cron path and the error. Since cron runs outside a connection, there is no ctx argument.

Was this page helpful?