An agent error people can act on: what failed, a countdown to the next automatic retry, Retry now and the raw details.
Set your access key from API keys as NEXTUI_TOKEN in .env.local and add the @nextui namespace below to components.json once. Then every item installs by name. Each install counts as a copy on a free account.
$pnpm dlx shadcn@latest add @nextui/error-retry
1{2"registries": {3"@nextui": {4"url": "https://nextui.dev/r/{name}.json",5"headers": { "Authorization": "Bearer ${NEXTUI_TOKEN}" }6}7}8}
1"use client";23import { useState } from "react";4import { useChat } from "@ai-sdk/react";5import { ErrorRetry } from "@/components/nextui/error-retry";67export function ChatError() {8const { error, regenerate, clearError, status } = useChat();9const [attempt, setAttempt] = useState(1);10if (!error && status !== "submitted") return null;1112const rateLimited = /429|rate/i.test(error?.message ?? "");13return (14<ErrorRetry15kind={rateLimited ? "rate_limit" : "unknown"}16code={rateLimited ? "429" : undefined}17details={error?.message}18status={status === "submitted" ? "retrying" : attempt > 3 ? "failed" : "waiting"}19retryIn={rateLimited ? 10 : 3}20attempt={attempt}21maxAttempts={3}22onRetry={() => {23setAttempt((a) => a + 1);24regenerate();25}}26onDismiss={clearError}27/>28);29}
| Prop | Type | Default | Description |
|---|---|---|---|
| kind | "rate_limit" | "overloaded" | "network" | "tool" | "unknown" | "rate_limit" | Picks the icon and default title |
| title | string | – | Headline. Defaults to a plain name for the kind |
| message | string | – | One line on what happened and what happens next |
| code | string | "429" | Short code shown as a chip |
| details | string | – | Raw error text, shown under a Details toggle |
| status | "waiting" | "retrying" | "failed" | "resolved" | "waiting" | waiting counts down, retrying shows a spinner, failed has no automatic retries left, resolved shows a short success line |
| retryIn | number | 8 | Seconds before onRetry is called on its own. 0 turns the countdown off. People can cancel it |
| attempt | number | 1 | Which retry is next, shown as attempt N of maxAttempts. The countdown restarts when it changes |
| maxAttempts | number | 3 | Shown next to the attempt number |
| onRetry | () => void | – | Called by Retry now and when the countdown reaches zero |
| onDismiss | () => void | – | Called by the close button. Leave out to hide it |
| autoPlay | boolean | false | Loop a rate limit that succeeds on the second retry, for demos |
| className | string | – | Extra classes on the wrapper |
Sign in to see the code
Preview it freely. A free account copies code and prompts a few times a day.