README.md130 lines · main
1# Error Handling
2
3`ErrorMatcher` displays a typed API error. If the error was classified by `handleError` (i.e. it is an instance of a known error class), it shows matching troubleshooting steps. Otherwise it shows a generic error card.
4
5Classification happens in the data layer — `handleError` in `data/fetchers.ts` matches the error message against patterns and throws the appropriate error subclass (e.g. `ConnectionTimeoutError`). The component never does regex matching itself.
6
7The `title` always comes from the caller — the same error type can appear on different pages with different titles.
8
9## Usage
10
11```tsx
12import { ErrorMatcher } from 'components/interfaces/ErrorHandling/ErrorMatcher'
13
14{
15 isError && (
16 <ErrorMatcher title="Failed to load tables" error={error} supportFormParams={{ projectRef }} />
17 )
18}
19```
20
21Pass the full `error` object from React Query — not `error.message`. This lets `ErrorMatcher` check the error class and show the right troubleshooting steps.
22
23### Props
24
25| Prop | Type | Description |
26| ------------------- | ------------------------------- | ------------------------------------------------------------------ |
27| `title` | `string` | Displayed in the error card header. Set by the caller. |
28| `error` | `string \| { message: string }` | The error from React Query (pass the full object, not `.message`). |
29| `supportFormParams` | `Partial<SupportFormUrlKeys>` | Typed params for the support form URL (projectRef, category…). |
30| `className` | `string?` | Extra classes on the card. |
31
32`supportFormParams` is typed as `Partial<SupportFormUrlKeys>` — autocomplete shows all available fields (`projectRef`, `orgSlug`, `category`, `subject`, `message`, `error`, `sid`). The URL is built by `createSupportFormUrl()` from `SupportForm.utils.tsx`.
33
34## Adding a new error mapping
35
36**1. Add the error class to `types/api-errors.ts`**
37
38```ts
39export type KnownErrorType = 'connection-timeout' | 'your-error'
40
41export class YourError extends ResponseError {
42 readonly errorType = 'your-error' as const
43}
44
45export type ClassifiedError = ConnectionTimeoutError | FailedToRetrieveProjectsError | YourError
46```
47
48**2. Add a pattern entry to `data/error-patterns.ts`**
49
50```ts
51import { YourError } from 'types/api-errors'
52
53export const ERROR_PATTERNS: ErrorPattern[] = [
54 // existing...
55 {
56 pattern: /YOUR_ERROR_PATTERN/i,
57 ErrorClass: YourError,
58 },
59]
60```
61
62`handleError` picks this up automatically — any matching API error will be thrown as a `YourError` instance.
63
64**3. Create `errorMappings/YourError.tsx`**
65
66```tsx
67import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
68import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state'
69import { useSidebarManagerSnapshot } from 'state/sidebar-manager-state'
70
71import { TroubleshootingAccordion } from '../TroubleshootingAccordion'
72import {
73 FixWithAITroubleshootingSection,
74 TroubleshootingGuideSection,
75} from '../TroubleshootingSections'
76
77const ERROR_TYPE = 'your-error'
78const BUILD_PROMPT = () => `Describe the issue for the AI assistant.`
79
80export function YourErrorTroubleshooting() {
81 const { openSidebar } = useSidebarManagerSnapshot()
82 const aiSnap = useAiAssistantStateSnapshot()
83
84 return (
85 <TroubleshootingAccordion
86 errorType={ERROR_TYPE}
87 stepTitles={{ 1: 'Troubleshooting guide', 2: 'Debug with AI' }}
88 >
89 <TroubleshootingGuideSection
90 number={1}
91 errorType={ERROR_TYPE}
92 href="https://supabase.com/docs/guides/..."
93 />
94 <FixWithAITroubleshootingSection
95 number={2}
96 errorType={ERROR_TYPE}
97 buildPrompt={BUILD_PROMPT}
98 onDebugWithAI={(prompt) => {
99 openSidebar(SIDEBAR_KEYS.AI_ASSISTANT)
100 aiSnap.newChat({ initialMessage: prompt })
101 }}
102 />
103 </TroubleshootingAccordion>
104 )
105}
106```
107
108**4. Add it to `error-mappings.tsx`**
109
110```tsx
111import { YourErrorTroubleshooting } from './errorMappings/YourError'
112
113export const ERROR_MAPPINGS: Record<KnownErrorType, ErrorMapping> = {
114 // existing...
115 'your-error': {
116 id: 'your-error',
117 Troubleshooting: YourErrorTroubleshooting,
118 },
119}
120```
121
122That's it. `ErrorMatcher` picks it up automatically.
123
124## Available section components
125
126| Component | Props |
127| --------------------------------------- | ------------------------------------------------------- |
128| `RestartDatabaseTroubleshootingSection` | `number`, `errorType`, `onRestartProject?` |
129| `TroubleshootingGuideSection` | `number`, `errorType`, `href`, `title?`, `description?` |
130| `FixWithAITroubleshootingSection` | `number`, `errorType`, `buildPrompt`, `onDebugWithAI?` |
Preview

Error Handling

ErrorMatcher displays a typed API error. If the error was classified by handleError (i.e. it is an instance of a known error class), it shows matching troubleshooting steps. Otherwise it shows a generic error card.

Classification happens in the data layer — handleError in data/fetchers.ts matches the error message against patterns and throws the appropriate error subclass (e.g. ConnectionTimeoutError). The component never does regex matching itself.

The title always comes from the caller — the same error type can appear on different pages with different titles.

Usage

import { ErrorMatcher } from 'components/interfaces/ErrorHandling/ErrorMatcher'

{
  isError && (
    <ErrorMatcher title="Failed to load tables" error={error} supportFormParams={{ projectRef }} />
  )
}

Pass the full error object from React Query — not error.message. This lets ErrorMatcher check the error class and show the right troubleshooting steps.

Props

PropTypeDescription
titlestringDisplayed in the error card header. Set by the caller.
errorstring | { message: string }The error from React Query (pass the full object, not .message).
supportFormParamsPartial<SupportFormUrlKeys>Typed params for the support form URL (projectRef, category…).
classNamestring?Extra classes on the card.

supportFormParams is typed as Partial<SupportFormUrlKeys> — autocomplete shows all available fields (projectRef, orgSlug, category, subject, message, error, sid). The URL is built by createSupportFormUrl() from SupportForm.utils.tsx.

Adding a new error mapping

1. Add the error class to types/api-errors.ts

export type KnownErrorType = 'connection-timeout' | 'your-error'

export class YourError extends ResponseError {
  readonly errorType = 'your-error' as const
}

export type ClassifiedError = ConnectionTimeoutError | FailedToRetrieveProjectsError | YourError

2. Add a pattern entry to data/error-patterns.ts

import { YourError } from 'types/api-errors'

export const ERROR_PATTERNS: ErrorPattern[] = [
  // existing...
  {
    pattern: /YOUR_ERROR_PATTERN/i,
    ErrorClass: YourError,
  },
]

handleError picks this up automatically — any matching API error will be thrown as a YourError instance.

3. Create errorMappings/YourError.tsx

import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state'
import { useSidebarManagerSnapshot } from 'state/sidebar-manager-state'

import { TroubleshootingAccordion } from '../TroubleshootingAccordion'
import {
  FixWithAITroubleshootingSection,
  TroubleshootingGuideSection,
} from '../TroubleshootingSections'

const ERROR_TYPE = 'your-error'
const BUILD_PROMPT = () => `Describe the issue for the AI assistant.`

export function YourErrorTroubleshooting() {
  const { openSidebar } = useSidebarManagerSnapshot()
  const aiSnap = useAiAssistantStateSnapshot()

  return (
    <TroubleshootingAccordion
      errorType={ERROR_TYPE}
      stepTitles={{ 1: 'Troubleshooting guide', 2: 'Debug with AI' }}
    >
      <TroubleshootingGuideSection
        number={1}
        errorType={ERROR_TYPE}
        href="https://supabase.com/docs/guides/..."
      />
      <FixWithAITroubleshootingSection
        number={2}
        errorType={ERROR_TYPE}
        buildPrompt={BUILD_PROMPT}
        onDebugWithAI={(prompt) => {
          openSidebar(SIDEBAR_KEYS.AI_ASSISTANT)
          aiSnap.newChat({ initialMessage: prompt })
        }}
      />
    </TroubleshootingAccordion>
  )
}

4. Add it to error-mappings.tsx

import { YourErrorTroubleshooting } from './errorMappings/YourError'

export const ERROR_MAPPINGS: Record<KnownErrorType, ErrorMapping> = {
  // existing...
  'your-error': {
    id: 'your-error',
    Troubleshooting: YourErrorTroubleshooting,
  },
}

That's it. ErrorMatcher picks it up automatically.

Available section components

ComponentProps
RestartDatabaseTroubleshootingSectionnumber, errorType, onRestartProject?
TroubleshootingGuideSectionnumber, errorType, href, title?, description?
FixWithAITroubleshootingSectionnumber, errorType, buildPrompt, onDebugWithAI?