Skip to content

shadcn.io is not affiliated with official shadcn/ui

Components

Free

Stack Trace for Ark UI

A failed tool call and its stack frames. For React with Ark UI, an error Trace line that opens on the frames, with no component of its own.

A tool call that threw shows up as one line in the error color, "Failed: TypeError: …", and opens on the stack frames, your own first.

Use it when a call fails with a stack the reader can act on: the frames say which file and line to open. The line is a Trace line with status="error" that expands into the frames, so there is no Stack Trace component to install in React. The title truncates, so repeat the full error at the top of the content, keep the frames from node_modules muted so yours stand out, and only send a stack from a development server: it shows your server's file paths.

Preview width

Installation

Stack Trace is a pattern. The command adds the parts it's built from, Trace and Code Block for the output of the calls around it, and the code to copy is the demo's.

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

Anatomy

Stack Trace anatomy: trace, line, icon, trigger, content, frame
Trace
└── TraceCollapsible
    ├── TraceCollapsibleTrigger
    │   └── TraceLine (status="error")
    │       ├── TraceIcon
    │       └── TraceTitle (Failed: the error)
    └── TraceCollapsibleContent
        └── div (bg-muted, font-mono)
            ├── p (the full error)
            └── ol (one li per frame)

Usage

import { CircleXIcon } from "lucide-react";
import {
  Trace, TraceCollapsible, TraceCollapsibleContent,
  TraceCollapsibleTrigger, TraceIcon, TraceLine, TraceTitle,
} from "@/components/ui/trace";
export function StackTrace(props: { stack: string }) {
  const [error, ...frames] = props.stack.split("\n").map((line) => line.trim());

  return (
    <Trace>
      <TraceCollapsible>
        <TraceCollapsibleTrigger>
          <TraceLine status="error">
            <TraceIcon>
              <CircleXIcon aria-hidden="true" />
            </TraceIcon>
            <TraceTitle>Failed: {error}</TraceTitle>
          </TraceLine>
        </TraceCollapsibleTrigger>
        <TraceCollapsibleContent>
          <div className="flex flex-col gap-2 rounded-md bg-muted p-3 font-mono text-xs">
            <p className="text-destructive">{error}</p>
            <ol>
              {frames.map((frame) => (
                <li
                  className={
                    frame.includes("node_modules") ? undefined : "text-foreground"
                  }
                  key={frame}
                >
                  {frame}
                </li>
              ))}
            </ol>
          </div>
        </TraceCollapsibleContent>
      </TraceCollapsible>
    </Trace>
  );
}

The first line of a stack is the error and each line after it a frame. A frame from node_modules keeps the content's muted color, and yours take text-foreground, so the frames you can fix stand out.

Demos

Your own frames as links that open the file at the line, and the framework's folded into a line of their own, so the frames you can fix come first. Each of your frames is a TraceLine in an anchor, "formatInvoice in app/lib/billing.ts:42"; point the link at your editor or your repository's file view.

Preview width

AI SDK

When a tool throws, its part is output-error. By default errorText is only the error's message, with no frames. Return error.stack from onError in toUIMessageStreamResponse to send them.

app/api/chat/route.ts
return result.toUIMessageStreamResponse({
  onError: (error) =>
    error instanceof Error ? (error.stack ?? error.message) : String(error),
});

A stack shows file paths from your server, so only send it in development. On the client, split errorText into the error and its frames.

if (part.state === "output-error") {
  const [error, ...frames] = part.errorText
    .split("\n")
    .map((line) => line.trim());

  return <TraceCollapsible>…</TraceCollapsible>;
}

Map the other tool states as in Tool.

Migrating from AI SDK Elements

If you added Stack Trace from AI SDK Elements (opens in a new tab), your project has a components/ai-elements/stack-trace.tsx wrapper. Paste this prompt into your coding agent to rebuild it on Trace. Every export keeps its name and props, so the code that uses it keeps working.

Prompt
Migrate components/ai-elements/stack-trace.tsx from AI SDK Elements to the shadcn.io Trace component.

Keep every export, with the same name and props, so the code that imports it keeps working. Only change how each part renders.

1. Read https://kit.dev/ui/ark/stack-trace.md and build Stack Trace the same way. If the project hasn't got Trace, run the command in its Installation section.
2. Rebuild each part:
   - StackTrace renders a Trace with a TraceCollapsible. Keep trace, open, defaultOpen, onOpenChange and onFilePathClick, and the parsing. Pass open and defaultOpen to the TraceCollapsible, and call onOpenChange with details.open from its onOpenChange.
   - StackTraceHeader renders a TraceCollapsibleTrigger with a TraceLine with status="error" and a TraceIcon.
   - StackTraceError renders a TraceTitle, like "Failed: TypeError: …". Keep StackTraceErrorType and StackTraceErrorMessage as spans inside it.
   - StackTraceContent renders a TraceCollapsibleContent.
   - StackTraceFrames renders the frames as a list in a muted, monospace block. Dim the frames from node_modules, and keep the file path buttons.
   - StackTraceExpandButton renders nothing, since the whole line opens the frames.
   - Buttons cannot sit inside a trigger. Render StackTraceActions and StackTraceCopyButton next to the TraceCollapsibleTrigger, not inside it.
3. Remove the imports the file no longer uses.
4. Run the type checker and fix any errors.

FAQ

What does installing Stack Trace add in React?

Trace and Code Block: the error line and its frames are Trace's, and the output of the calls that ran before it is a Code Block. Stack Trace is a pattern, so no stack-trace file lands in your ui folder: copy the demo's code into your own component and its frame parser with it. The command uses the shadcn CLI.

How do I split a stack into the error and its frames?

Split it on new lines and trim each: the first line is the error, "TypeError: …", and every line after it a frame, "at seedUsers (prisma/seed.ts:27:34)". The demos read each frame's function, file and line with one regular expression, and keep the raw line for a frame it doesn't match.

Why are some frames muted or folded away?

They come from code the reader can't fix: node_modules, or Node's own node: modules. Muting them, or folding them into a line of their own as the Frame Links demo does, puts the frames from your code first, where the bug usually is.

Should the stack start open?

When it is the call that ended the reply, yes: the main demo opens the failed call as soon as it fails, with defaultOpen, so the error and your frames are in view. Leave the framework frames closed, since they are rarely the place to look.

Is it safe to send a stack to the browser?

Only in development. A stack holds your server's file paths and function names. With the AI SDK, errorText is just the message unless you return error.stack from onError; do that behind a check for the development environment.

Can the reader open the frames with the keyboard?

Yes. The error line is a button: Tab reaches it, and Enter or Space opens or closes it. Inside, each of your frames is a link, so Tab moves through them in order, and Enter follows one.

Is this the same as AI SDK Elements' Stack Trace?

It does the same job without a wrapper: Stack Trace was a card with its own header, copy button and frame list, and here it is an error Trace line that opens on the frames. The Migrating from AI SDK Elements section has a prompt that rebuilds the old file on Trace and keeps its exports.

API Reference

Stack Trace has no props of its own. The failed call is a Trace collapsible with status="error" on its TraceLine, and the output of the calls that ran is a Code Block.