or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

examples

edge-cases.mdreal-world-scenarios.md
index.md
tile.json

error-handling.mddocs/reference/

Error Handling and Flow Control

SvelteKit provides functions for creating HTTP errors, redirects, form failures, and validation errors to control application flow. These functions throw special error objects that SvelteKit catches and handles appropriately.

Capabilities

HTTP Errors

Throw an HTTP error with a status code to trigger error handling.

/**
 * Throws an HttpError with the given status code and body
 * @param status - HTTP status code (400-599)
 * @param body - Optional error body with message and additional properties
 * @throws {HttpError}
 */
function error(
  status: number,
  body?: { message: string; [key: string]: any }
): never;

Usage Example:

import { error } from '@sveltejs/kit';
import type { RequestEvent } from '@sveltejs/kit';

export async function load({ params }: { params: { id: string } }) {
  const post = await getPost(params.id);

  if (!post) {
    error(404, { message: 'Post not found' });
  }

  return { post };
}

// With additional error properties
export async function DELETE(event: RequestEvent) {
  const item = await getItem(event.params.id);

  if (item.protected) {
    error(403, {
      message: 'Cannot delete protected item',
      reason: 'PROTECTED_RESOURCE'
    });
  }
}

Check HTTP Errors

Check if an error is an HttpError, optionally with a specific status code.

/**
 * Type guard to check if an error is an HttpError
 * @param e - The error to check
 * @param status - Optional specific status code to match
 * @returns true if e is an HttpError (with matching status if provided)
 */
function isHttpError(e: unknown, status?: number): boolean;

Usage Example:

import { isHttpError } from '@sveltejs/kit';

try {
  await someOperation();
} catch (e) {
  if (isHttpError(e)) {
    console.log('HTTP error occurred:', e.status);
  }

  // Check for specific status
  if (isHttpError(e, 404)) {
    console.log('Resource not found');
  }
}

Redirects

Throw a redirect to navigate to a different URL.

/**
 * Throws a Redirect with the given status code and location
 * @param status - Redirect status code (300-308, typically 303 or 307)
 * @param location - Target URL as string or URL object
 * @throws {Redirect}
 */
function redirect(status: number, location: string | URL): never;

Usage Example:

import { redirect } from '@sveltejs/kit';

// Redirect after form submission (303 for POST-to-GET)
export const actions = {
  default: async ({ request }) => {
    const data = await request.formData();
    await saveData(data);
    redirect(303, '/success');
  }
};

// Redirect in load function (307 to preserve method)
export async function load({ locals }) {
  if (!locals.user) {
    redirect(307, '/login');
  }

  return { user: locals.user };
}

// Redirect to external URL
export async function GET() {
  redirect(302, 'https://external-site.com/resource');
}

Check Redirects

Check if an error is a Redirect.

/**
 * Type guard to check if an error is a Redirect
 * @param e - The error to check
 * @returns true if e is a Redirect
 */
function isRedirect(e: unknown): boolean;

Usage Example:

import { isRedirect } from '@sveltejs/kit';

try {
  await loadData();
} catch (e) {
  if (isRedirect(e)) {
    console.log('Redirect to:', e.location);
    // Let SvelteKit handle the redirect
    throw e;
  }
  // Handle other errors
}

Form Failures

Create an ActionFailure to return validation errors or failure data from form actions.

/**
 * Creates an ActionFailure for form submissions
 * @param status - HTTP status code (400-599, typically 400)
 * @param data - Optional failure data to return to client
 * @returns ActionFailure object that SvelteKit handles specially
 */
function fail<T extends Record<string, any> | undefined>(
  status: number,
  data?: T
): ActionFailure<T>;

Usage Example:

import { fail } from '@sveltejs/kit';
import type { Actions } from './$types';

export const actions = {
  login: async ({ request }) => {
    const data = await request.formData();
    const email = data.get('email');
    const password = data.get('password');

    if (!email) {
      return fail(400, {
        email,
        missing: true,
        message: 'Email is required'
      });
    }

    const user = await authenticate(email, password);

    if (!user) {
      return fail(401, {
        email,
        incorrect: true,
        message: 'Invalid credentials'
      });
    }

    return { success: true };
  }
} satisfies Actions;

Check Action Failures

Check if an error is an ActionFailure.

/**
 * Type guard to check if an error is an ActionFailure
 * @param e - The error to check
 * @returns true if e is an ActionFailure
 */
function isActionFailure(e: unknown): boolean;

Usage Example:

import { isActionFailure } from '@sveltejs/kit';

try {
  const result = await performAction();
} catch (e) {
  if (isActionFailure(e)) {
    console.log('Action failed with status:', e.status);
    console.log('Failure data:', e.data);
  }
}

Validation Errors

Throw a validation error with detailed validation issues for imperatively failing form validation.

/**
 * Throws a ValidationError with the given validation issues
 * @param issues - Array of validation issues or simple string messages
 * @throws {ValidationError}
 * @since 2.47.3
 */
function invalid(...issues: (StandardSchemaV1.Issue | string)[]): never;

Usage Example:

import { invalid } from '@sveltejs/kit';
import type { Actions } from './$types';

export const actions = {
  register: async ({ request }) => {
    const data = await request.formData();
    const email = data.get('email');
    const age = data.get('age');

    const issues = [];

    if (!email || !email.includes('@')) {
      issues.push({
        path: ['email'],
        message: 'Valid email is required'
      });
    }

    if (!age || parseInt(age) < 18) {
      issues.push({
        path: ['age'],
        message: 'Must be 18 or older'
      });
    }

    if (issues.length > 0) {
      invalid(...issues);
    }

    // Continue with registration
  },

  // Simple string messages (no path)
  login: async ({ request }) => {
    const data = await request.formData();
    const username = data.get('username');
    const password = data.get('password');

    const success = await tryLogin(username, password);
    if (!success) {
      invalid('Incorrect username or password');
    }

    // Continue with login
  }
} satisfies Actions;

Check Validation Errors

Check if an error is a ValidationError.

/**
 * Type guard to check if an error is a ValidationError
 * @param e - The error to check
 * @returns true if e is a ValidationError
 * @since 2.47.3
 */
function isValidationError(e: unknown): boolean;

Usage Example:

import { isValidationError } from '@sveltejs/kit';

try {
  await validateAndProcess();
} catch (e) {
  if (isValidationError(e)) {
    console.log('Validation failed with issues:', e.issues);
    e.issues.forEach(issue => {
      console.log(`Field ${issue.path.join('.')}: ${issue.message}`);
    });
  }
}

Types

interface HttpError {
  status: number;
  body: { message: string; [key: string]: any };
}

interface Redirect {
  status: number;
  location: string;
}

interface ActionFailure<T extends Record<string, any> | undefined = Record<string, any> | undefined> {
  status: number;
  data: T;
}

interface ValidationError {
  issues: StandardSchemaV1.Issue[];
}

/**
 * Standard Schema V1 validation issue format
 * From @standard-schema/spec package
 */
interface StandardSchemaV1.Issue {
  message: string;
  path?: (string | number)[];
}

Notes

  • All error throwing functions (error, redirect, invalid) have return type never because they always throw
  • Use error() in load functions, request handlers, and hooks
  • Use redirect() for navigation after successful operations (303) or access control (307)
  • Use fail() in form actions to return validation errors without throwing
  • Use invalid() in form actions for declarative validation with detailed error paths
  • Status code conventions:
    • 303: Redirect after successful POST (clears form)
    • 307/308: Redirect preserving request method
    • 400: Bad request / validation failure
    • 401: Unauthorized
    • 403: Forbidden
    • 404: Not found
    • 500: Internal server error