Harness-engineering svelte-error-pages

Svelte Error Pages

install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/claude-code/svelte-error-pages" ~/.claude/skills/intense-visions-harness-engineering-svelte-error-pages && rm -rf "$T"
manifest: agents/skills/claude-code/svelte-error-pages/SKILL.md
source content

Svelte Error Pages

Handle 404s, auth failures, and unexpected crashes in SvelteKit with +error.svelte, the error() helper, and handleError hooks

When to Use

  • You need to show a custom error page for 404s, 403s, or other HTTP errors thrown in load functions
  • You want to customize the error UI per route segment (nested error boundaries)
  • You need to capture unexpected server errors and report them to an error tracking service
  • You are unsure when to use
    error()
    vs. throwing raw errors vs. returning
    fail()

Instructions

Defining error pages:

  1. Create
    +error.svelte
    in any route directory. It catches errors thrown by the load functions in that route segment and all its children:
<!-- src/routes/+error.svelte — global error boundary -->
<script lang="ts">
  import { page } from '$app/stores'
</script>

<h1>{$page.status}: {$page.error?.message}</h1>

{#if $page.status === 404}
  <p>This page doesn't exist.</p>
  <a href="/">Go home</a>
{:else}
  <p>Something went wrong. Please try again.</p>
{/if}
  1. Add nested
    +error.svelte
    files for section-specific error UIs. The nearest ancestor
    +error.svelte
    catches the error:
routes/
  +error.svelte           → global fallback
  blog/
    +error.svelte         → blog-specific errors
    [slug]/
      +page.server.ts     → throws error(404)
                            → caught by blog/+error.svelte

Throwing expected errors:

  1. Use the
    error
    helper from
    @sveltejs/kit
    for expected, anticipated errors (404, 401, 403). These are shown to the user via
    +error.svelte
    :
// +page.server.ts
import { error } from '@sveltejs/kit';

export const load: PageServerLoad = async ({ params }) => {
  const post = await db.post.findUnique({ where: { slug: params.slug } });

  if (!post) throw error(404, 'Post not found');
  if (!post.published) throw error(403, 'This post is not published');

  return { post };
};
  1. Pass a structured message object instead of a string for richer error data:
throw error(422, { message: 'Validation failed', field: 'email' });

Access in

+error.svelte
:

<p>{$page.error?.message}</p>

Unexpected errors:

  1. Unhandled exceptions (thrown objects that are not SvelteKit errors) are treated as 500 errors. SvelteKit will NOT expose the error message to the client — only the
    handleError
    hook's return value is shown:
// This exception message is NEVER shown to users
throw new Error('Database connection string exposed!');

// handleError in hooks.server.ts controls what users see:
export const handleError: HandleServerError = ({ error }) => {
  return { message: 'An internal error occurred. Please try again.' };
};

Redirecting from error pages:

  1. Throw
    redirect
    from
    @sveltejs/kit
    to navigate the user rather than showing an error:
import { redirect } from '@sveltejs/kit';

export const load: PageServerLoad = async ({ locals }) => {
  if (!locals.user) redirect(303, '/login');
  return { user: locals.user };
};

Custom error shape:

  1. Extend the
    App.Error
    interface to add fields to
    $page.error
    :
// src/app.d.ts
declare global {
  namespace App {
    interface Error {
      message: string;
      errorId?: string;
      code?: string;
    }
  }
}
// hooks.server.ts
export const handleError: HandleServerError = async ({ error, status }) => {
  const errorId = crypto.randomUUID();
  await reportError(error, errorId);
  return {
    message: status === 404 ? 'Page not found' : 'Something went wrong',
    errorId,
  };
};
<!-- +error.svelte -->
{#if $page.error?.errorId}
  <small>Error ID: {$page.error.errorId}</small>
{/if}

Details

Expected vs. unexpected errors:

TypeHow thrownUser seesLogged
Expected
throw error(4xx, msg)
The message directlyNo (by design)
Unexpected
throw new Error(...)
handleError
return value
Yes (via
handleError
)
Redirect
throw redirect(3xx, url)
NavigationNo

error() vs. fail():

  • error()
    — terminates the load function, shows the
    +error.svelte
    page
  • fail()
    — only valid in form actions, re-renders the page with error data in the
    form
    prop

Never use

fail()
in load functions; never use
error()
in actions when you want to re-display the form.

Layout-level errors:

If an error is thrown in a layout load function, the nearest ancestor

+error.svelte
catches it — not a sibling of the layout. This means errors in
(app)/+layout.server.ts
render the
(app)/+error.svelte
, not the root
+error.svelte
.

The root error page:

The root

src/routes/+error.svelte
is the last resort. If this page itself throws an error, SvelteKit falls back to a static error page generated from
src/error.html
(if it exists) or a plain text response.

$page.status:

The

$page.status
reactive value reflects the HTTP status code of the current page, including error pages. Use it to render different UI for 404 vs. 500 errors.

Source

https://kit.svelte.dev/docs/errors

Process

  1. Read the instructions and examples in this document.
  2. Apply the patterns to your implementation, adapting to your specific context.
  3. Verify your implementation against the details and edge cases listed above.

Harness Integration

  • Type: knowledge — this skill is a reference document, not a procedural workflow.
  • No tools or state — consumed as context by other skills and agents.

Success Criteria

  • The patterns described in this document are applied correctly in the implementation.
  • Edge cases and anti-patterns listed in this document are avoided.