# ChatError

> Quiet inline failure banner for a chat turn: the error, an optional detail line, and a retry button that disables itself while the retry is in flight.

- Package: `fancy-ui-svelte` (Svelte 5 + Tailwind CSS v4)
- Category: AI Chat
- Tags: ai, chat, error, feedback, retry
- Docs: https://fancy-ui.rama.app/docs/components/chat-error
- Source: https://github.com/RamaHerbin/fancy-ui/tree/main/src/lib/fancy-ui/chat-error

## Import

```svelte
<script lang="ts">
  import { ChatError } from 'fancy-ui-svelte';
</script>
```

Setup (once per project): `npm install fancy-ui-svelte`, then add `@import "fancy-ui-svelte/tailwind.css";` after `@import "tailwindcss";` in your main CSS file. Full guide: https://fancy-ui.rama.app/llms.txt

React: `import { ChatError } from 'fancy-ui-react';` (same prop names; `class` becomes `className`, snippets become `ReactNode`).

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `message` | `string` | `"Something went wrong"` | The failure line |
| `detail` | `string` | — | Secondary muted line under the message, e.g. the error code |
| `onRetry` | `() => void` | — | Pressing retry calls this; the retry button only exists when it is set |
| `retryLabel` | `string` | `"Retry"` | Label for the retry button |
| `retrying` | `boolean` | `false` | Whether a retry is in flight: disables the button and marks the row busy |
| `sound` | `boolean` | `false` | Plays the press cue on retry, once the user has enabled sound |

## Snippets

| Snippet | Description |
| --- | --- |
| `icon` | Leading icon, replacing the default warning triangle |
| `children` | Rendered instead of the message and detail block |

## Examples

### Basic Usage

```svelte
<script lang="ts">
	import { onMount } from "svelte";
	import { ChatError } from "fancy-ui-svelte";

	/** How long the pretend request takes before it comes back green. */
	const RETRY_MS = 1500;

	let phase = $state<"failed" | "retrying" | "recovered">("failed");
	let timer: ReturnType<typeof setTimeout> | undefined;

	function retry() {
		phase = "retrying";
		timer = setTimeout(() => {
			timer = undefined;
			phase = "recovered";
		}, RETRY_MS);
	}

	function replay() {
		clearTimeout(timer);
		timer = undefined;
		phase = "failed";
	}

	// The pending retry outlives nothing: clear it if the reader navigates away
	// mid-flight.
	onMount(() => () => clearTimeout(timer));
</script>

<div class="flex w-full max-w-md flex-col gap-3 p-6">
	<div class="bg-primary text-primary-foreground ml-auto rounded-2xl rounded-br-sm px-4 py-2.5">
		<p class="text-sm">What changed in yesterday's deploy?</p>
	</div>

	{#if phase === "recovered"}
		<div class="bg-muted mr-auto rounded-2xl rounded-bl-sm px-4 py-2.5">
			<p class="text-sm leading-relaxed">
				Three commits landed: a cache fix, the new export endpoint, and a dependency bump.
			</p>
		</div>
		<button
			type="button"
			class="text-muted-foreground hover:text-foreground self-start text-xs underline underline-offset-4"
			onclick={replay}
		>
			Replay the failure
		</button>
	{:else}
		<ChatError
			sound
			message="The assistant couldn't finish that reply"
			detail="network_error · request 8f21c0"
			onRetry={retry}
			retrying={phase === "retrying"}
		/>
	{/if}
</div>
```
