Files
supabase/apps/studio/components/interfaces/ErrorHandling
Danny WhiteandAli Waseem 12a43e5aba chore(studio): storage file explorer breadcrumbs (#43844)
## What kind of change does this PR introduce?

UI update that resolves DEPR-114. Also resolves DEPR-113.

## What is the current behavior?

- The breadcrumbs on the file explorer have some rough edges in column
view
  - Fancy hide/show behavior
  - Hidden tap targets
- `FileExplorerHeader` actions can overflow on the x-axis
- The Navigate button is only shown on hover
- The inline Navigate flow does not work well on smaller screens

## What is the new behavior?

- Column view now shows the same in-explorer breadcrumb trail as list
view
- The active breadcrumb is visually emphasized, while inactive
breadcrumbs remain clickable
- The back affordance now uses a clearer arrow treatment with a stronger
separator from the breadcrumb trail
- The Navigate button is permanently visible and moved to the right-side
action group before Reload
- Navigate now opens a dialog on both desktop and mobile
- Added typed telemetry so we can measure `Navigate` usage before
deciding whether to keep or remove it
- Fixed header overflow by letting the full header contents scroll
horizontally together instead of visibly spilling out

| Before | After |
| --- | --- |
| <img width="947" height="997" alt="Buckets Storage AWS Healthy
Toolshed Supabase"
src="https://github.com/user-attachments/assets/fa53fdd4-954c-4832-bf9b-210b63ae020b"
/> | <img width="947" height="997" alt="Buckets Storage AWS Healthy
Toolshed Supabase"
src="https://github.com/user-attachments/assets/3689a0e5-97d1-4b36-a2dd-7adce23add5d"
/> |
| <img width="864" height="997" alt="Buckets Storage AWS Healthy
Toolshed Supabase"
src="https://github.com/user-attachments/assets/ad559118-205f-40e2-b3c5-97cef462d5f5"
/> | <img width="864" height="997" alt="Buckets Storage AWS Healthy
Toolshed Supabase"
src="https://github.com/user-attachments/assets/9c569b29-7c58-4a33-b809-34d6ed919008"
/> |

## Additional context

Also added a link to the `Buckets` portion of the `PageHeader`
breadcrumb:

```text
Files > Buckets > MyBucketName
```

It goes to the same place as Files because the root Files page lists
buckets, but having both links there feels more ergonomic in practice.

---------

Co-authored-by: Ali Waseem <waseema393@gmail.com>
2026-03-30 13:14:27 +11:00
..

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

Prop Type Description
title string Displayed in the error card header. Set by the caller.
error string | { message: string } The error from React Query (pass the full object, not .message).
supportFormParams Partial<SupportFormUrlKeys> Typed params for the support form URL (projectRef, category…).
className string? 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

Component Props
RestartDatabaseTroubleshootingSection number, errorType, onRestartProject?
TroubleshootingGuideSection number, errorType, href, title?, description?
FixWithAITroubleshootingSection number, errorType, buildPrompt, onDebugWithAI?