Error Handling
This guide explains how to handle gau errors.
GauError Class
Section titled “GauError Class”All errors thrown by gau handlers are GauError instances with a specific error code. You can import and use these in your own code:
import { GauError, ErrorCodes } from '@rttnd/gau'
// Using default message and statusthrow new GauError(ErrorCodes.UNAUTHORIZED)
// With options onlythrow new GauError(ErrorCodes.CSRF_INVALID, { redirectUrl: '/login' })
// With custom messagethrow new GauError(ErrorCodes.PROVIDER_NOT_FOUND, `Provider "${id}" not found`)Configuring Error Handling
Section titled “Configuring Error Handling”onError Hook
Section titled “onError Hook”The onError hook lets you customize how errors are handled. You can log errors, modify responses, or redirect users to specific pages based on the error type.
import { createAuth, ErrorCodes, redirect } from '@rttnd/gau'
const auth = createAuth({ // ... other options
onError: ({ error, request }) => { // Log all auth errors console.error('Auth error:', error.code, error.message)
// Return a Response to override default behavior if (error.code === ErrorCodes.CSRF_INVALID) { return redirect('/login?error=session_expired') }
// Return undefined to fall back to errorRedirect or default behavior },})errorRedirect Option
Section titled “errorRedirect Option”For user-facing errors (OAuth flow), you can specify a URL to redirect to. Error details are passed as query parameters.
const auth = createAuth({ // Redirect user-facing errors to your custom error page errorRedirect: '/auth/error',})Error Response Formats
Section titled “Error Response Formats”Gau uses route-based detection to determine whether to return HTML or JSON:
| Request Type | Example Routes | Default Response |
|---|---|---|
| User-facing | GET /:provider, GET /callback/:provider | HTML error page or redirect |
| API | GET /session, POST /signout | JSON: { error: 'message', code: 'ERROR_CODE' } |
Response Priority
Section titled “Response Priority”- If
onErrorreturns aResponse, that’s used - For user-facing requests with
errorRedirectset, redirects with query params - Otherwise, renders a styled HTML error page (user-facing) or returns JSON (API)
Creating an Error Page
Section titled “Creating an Error Page”When using errorRedirect, gau passes these query parameters:
code- The error code (e.g.,CSRF_INVALID)message- Human-readable error messagestatus- HTTP status coderedirect- Optional URL to redirect back to
<script lang="ts"> import { page } from '$app/state' import { ErrorCodes, type ErrorCode } from '@rttnd/gau'
const code = $derived(page.url.searchParams.get('code') as ErrorCode | null) const message = $derived(page.url.searchParams.get('message')) const redirect = $derived(page.url.searchParams.get('redirect') || '/')</script>
<svelte:head> <title>Authentication Error</title></svelte:head>
<div class="error-container"> <h1>Authentication Error</h1> <p class="message">{message}</p> {#if code} <p class="code">{code}</p> {/if} <a href={redirect}>Go back</a></div>import { useSearchParams } from '@solidjs/router'import type { ErrorCode } from '@rttnd/gau'
export default function AuthErrorPage() { const [params] = useSearchParams()
const code = () => params.code as ErrorCode | undefined const message = () => params.message const redirect = () => params.redirect || '/'
return ( <div class="error-container"> <h1>Authentication Error</h1> <p class="message">{message()}</p> {code() && <p class="code">{code()}</p>} <a href={redirect()}>Go back</a> </div> )}Handling Errors in Client Code
Section titled “Handling Errors in Client Code”When making API calls, errors are returned as JSON:
const response = await fetch('/api/auth/session')const data = await response.json()
if ('error' in data) { console.error('Error:', data.code, data.error) // data.code is the error code (e.g., 'UNAUTHORIZED') // data.error is the human-readable message}Checking for Specific Errors
Section titled “Checking for Specific Errors”import { ErrorCodes } from '@rttnd/gau'
if (data.code === ErrorCodes.UNAUTHORIZED) { // Redirect to login}
if (data.code === ErrorCodes.ACCOUNT_ALREADY_LINKED) { // Show "account already linked" message}Error Codes Reference
Section titled “Error Codes Reference”OAuth Flow Errors
Section titled “OAuth Flow Errors”| Code | Default Message | Status |
|---|---|---|
CSRF_INVALID | Invalid CSRF token | 403 |
PKCE_MISSING | Missing PKCE code verifier | 400 |
PKCE_CHALLENGE_MISSING | Missing PKCE challenge | 400 |
OAUTH_CANCELLED | Authentication was cancelled | 200 |
PROVIDER_NOT_FOUND | Provider not found | 400 |
AUTHORIZATION_URL_FAILED | Could not create authorization URL | 500 |
Account/User Errors
Section titled “Account/User Errors”| Code | Default Message | Status |
|---|---|---|
USER_NOT_FOUND | User not found | 404 |
USER_CREATE_FAILED | Failed to create user | 500 |
ACCOUNT_ALREADY_LINKED | Account already linked to another user | 409 |
ACCOUNT_LINK_FAILED | Failed to link account | 500 |
ACCOUNT_NOT_LINKED | Account not linked | 400 |
CANNOT_UNLINK_LAST_ACCOUNT | Cannot unlink the last account | 400 |
EMAIL_ALREADY_EXISTS | An account with this email already exists | 409 |
EMAIL_MISMATCH | Email mismatch between existing account and provider | 400 |
LINKING_NOT_ALLOWED | Linking not allowed | 403 |
LINK_ONLY_PROVIDER | Sign-in with this provider is disabled… | 400 |
Session/Auth Errors
Section titled “Session/Auth Errors”| Code | Default Message | Status |
|---|---|---|
UNAUTHORIZED | Unauthorized | 401 |
FORBIDDEN | Forbidden | 403 |
SESSION_INVALID | Invalid session | 400 |
SESSION_VALIDATION_FAILED | Failed to validate session | 500 |
Token Errors
Section titled “Token Errors”| Code | Default Message | Status |
|---|---|---|
TOKEN_INVALID | Invalid token | 400 |
TOKEN_EXPIRED | Token expired | 400 |
CODE_VERIFIER_INVALID | Invalid code verifier | 400 |
Request Errors
Section titled “Request Errors”| Code | Default Message | Status |
|---|---|---|
NOT_FOUND | Not found | 404 |
METHOD_NOT_ALLOWED | Method not allowed | 405 |
INVALID_REQUEST | Invalid request | 400 |
INVALID_REDIRECT_URL | Invalid redirect URL | 400 |
UNTRUSTED_HOST | Untrusted redirect host | 400 |
UNKNOWN_PROFILE | Unknown profile | 400 |
Internal Errors
Section titled “Internal Errors”| Code | Default Message | Status |
|---|---|---|
INTERNAL_ERROR | An unexpected error occurred | 500 |
Disabling Error Redirect
Section titled “Disabling Error Redirect”If you prefer gau’s built-in styled error pages instead of redirecting, set errorRedirect to undefined:
const auth = createAuth({ errorRedirect: undefined, // Use gau's built-in error pages})