tRPC-SvelteKit v3.6.1

End-to-end typesafe APIs for your SvelteKit applications

Handling errors

Whenever an error occurs in a procedure, tRPC responds to the client with an object that includes an "error" property. This property contains all the information that you need to handle the error in the client. Here's an example of how you can handle the error in your SvelteKit page (look at the try/catch block in the handleSave function):

routes/authors/+page.svelte
<script lang="ts">
  import { invalidateAll } from '$app/navigation';
  import AuthorizationAlert from '$lib/components/AuthorizationAlert.svelte';
  import DataTable from '$lib/components/DataTable.svelte';
  import ModalEditor from '$lib/components/ModalEditor.svelte';
  import TextInput from '$lib/components/inputs/TextInput.svelte';
  import TextareaInput from '$lib/components/inputs/TextareaInput.svelte';
  import { trpc } from '$lib/trpc/client';
  import type { RouterInputs } from '$lib/trpc/router';
  import { TRPCClientError } from '@trpc/client';
  import type { PageData } from './$types';

  export let data: PageData;

  let busy = false;
  let item: RouterInputs['authors']['save'] | null; // 👈 we're using a helper type
  let errors: { message: string; path: string[] }[] | null = null;
  let needsAuthorization = false;

  const handleAdd = async () => {
    if (!data.isAuthenticated) {
      needsAuthorization = true;
      return;
    }

    item = { id: null, firstName: '', lastName: '', bio: '' };
  };

  const handleEdit = async (e: CustomEvent<string>) => {
    if (!data.isAuthenticated) {
      needsAuthorization = true;
      return;
    }

    busy = true;
    item = await trpc().authors.load.query(e.detail);
    busy = false;
  };

  const handleDelete = async (e: CustomEvent<string>) => {
    if (!data.isAuthenticated) {
      needsAuthorization = true;
      return;
    }

    busy = true;
    await trpc().authors.delete.mutate(e.detail);
    await invalidateAll();
    busy = false;
  };

  const handleCancel = () => {
    item = null;
    errors = null;
  };

  const handleSave = async (e: CustomEvent<RouterInputs['authors']['save']>) => {
    if (!data.isAuthenticated) {
      needsAuthorization = true;
      return;
    }

    busy = true;
    try {
      await trpc().authors.save.mutate(e.detail);
      item = null;
      await invalidateAll();
    } catch (err) {
      if (err instanceof TRPCClientError) {
        errors = JSON.parse(err.message);
      } else {
        throw err;
      }
    } finally {
      busy = false;
    }
  };
</script>

<svelte:head>
  <title>Authors • Bookstall</title>
</svelte:head>

<DataTable
  {busy}
  title="Authors"
  items={data.authors}
  columns={[
    {
      title: 'Name',
      grow: true,
      accessor: ({ firstName, lastName }) => `${firstName} ${lastName}`
    },
    {
      title: 'Books',
      align: 'right',
      accessor: (author) => author._count.books
    }
  ]}
  on:add={handleAdd}
  on:edit={handleEdit}
  on:delete={handleDelete}
/>

<ModalEditor {item} itemName="author" on:cancel={handleCancel} on:save={handleSave}>
  <div class="grid">
    <TextInput name="firstName" label="First name" required {errors} {item} />
    <TextInput name="lastName" label="Last name" required {errors} {item} />
  </div>
  <TextareaInput name="bio" label="Bio" {errors} {item} />
</ModalEditor>

<AuthorizationAlert visible={needsAuthorization} on:close={() => (needsAuthorization = false)} />

Please refer to the error handling page in the tRPC documentation for more information.

You can also supply an onError handler to the createTRPCHandle method in your hooks.server.ts, which could be useful, for instance, if you want to log all errors to a service like Sentry:

hooks.server.ts
import { createContext } from '$lib/trpc/context';
import { router } from '$lib/trpc/router';
import type { Handle } from '@sveltejs/kit';
import { createTRPCHandle } from 'trpc-sveltekit';

export const handle: Handle = createTRPCHandle({
  router,
  createContext,
  onError: ({ type, path, error }) =>
    console.error(`Encountered error while trying to process ${type} @ ${path}:`, error)
});