Epicenter
Local-first, open source apps
Stack Trace is a line for a tool call that failed. The error is the title, like "Failed: TypeError". Open it for the stack frames, which can link to the file and line.
Stack Trace is built with Trace with a Trace.Collapsible for the frames.
Installation
Stack Trace is built with the Trace and Code Block components.
Usage
<script lang="ts">
import * as Trace from "$lib/components/ui/trace/index.js";
const [error, ...frames] = stack.split("\n").map((line) => line.trim());
</script> <Trace.Root>
<Trace.Collapsible>
<Trace.CollapsibleTrigger>
<Trace.Line status="error">
<Trace.Icon>
<CircleXIcon />
</Trace.Icon>
<Trace.Title>Failed: {error}</Trace.Title>
</Trace.Line>
</Trace.CollapsibleTrigger>
<Trace.CollapsibleContent>
<div
class="flex flex-col gap-2 rounded-md bg-muted p-3 font-mono text-xs"
>
<p class="text-destructive">{error}</p>
<ol>
{#each frames as frame, index (index)}
<li
class={frame.includes("node_modules")
? undefined
: "text-foreground"}
>
{frame}
</li>
{/each}
</ol>
</div>
</Trace.CollapsibleContent>
</Trace.Collapsible>
</Trace.Root> The title truncates, so repeat the full error at the top of the content. Frames from node_modules stay muted, so your own frames stand out.
Frame Links
Turn your own frames into links that open the file at the line. Fold the framework frames into a collapsible line of their own, so the frames you can fix come first.
TypeError: Cannot read properties of undefined (reading 'total')
- at renderWithHooks (node_modules/react-dom/cjs/react-dom.development.js:14985:18)
- at beginWork (node_modules/react-dom/cjs/react-dom.development.js:19049:16)
- at performUnitOfWork (node_modules/react-dom/cjs/react-dom.development.js:22776:12)
- at workLoopSync (node_modules/react-dom/cjs/react-dom.development.js:22707:5)
AI SDK
When a tool throws, its part is output-error. By default errorText is only the error message, with no frames. Return error.stack from onError in toUIMessageStreamResponse to send them.
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.
{#if part.state === "output-error"}
{@const [error, ...frames] = part.errorText
.split("\n")
.map((line) => line.trim())}
<Trace.Collapsible>…</Trace.Collapsible>
{/if} Map the other tool states as in Tool.
API Reference
See Trace.