Stack Trace

Zeig einen Absturz so, wie Entwickler ihn lesen. Dein Code zuerst, Framework-Frames eingeklappt, die fehlerhafte Zeile im Kontext und jede Ursache der Reihe nach. Liest Stacks aus Node, Chrome, Firefox, Safari, Bun, Deno und Python, mit Kopieren, Im Editor öffnen und Beheben lassen.

Wenn der Befehl, Tool-Call oder Test eines Agenten fehlschlägt, steckt der nützliche Teil des Fehlers unter fünfzig Zeilen Framework-Interna. Stack Trace stellt Fehlertyp und Nachricht an den Anfang, zeigt deine eigenen Frames in vollem Kontrast mit Datei, Zeile und Spalte und faltet jede Folge von Framework-Frames zu einer ruhigen Zeile wie „8 framework frames · next“ zusammen.

parseStackTrace liest V8-Stacks aus Node, Chrome, Bun und Deno, Firefox- und Safari-Stacks, Vitest-Frames samt dem Code darunter und Python-Tracebacks, einschließlich verketteter Ursachen aus [cause], Caused by: und den Python-Abschnitten „direct cause“ und „during handling“. node_modules, node:internal, Next.js-Interna, site-packages und die Standardbibliothek gelten als Code außerhalb der App, und file://- und webpack-internal-Pfade werden zu lesbaren Projektpfaden. Zeilen, die er nicht erkennt, bleiben erhalten und werden nie verworfen.

Der Frame, in dem dein Code fehlschlug, kann seinen Quelltext mit hervorgehobener Fehlerzeile zeigen, über Code Block. Lange Nachrichten werden mit Show more gekürzt, Copy liefert den Originaltext, und Frames öffnen sich über getFrameHref oder onFrameClick in deinem Editor. Die kompakte Variante ist eine einzelne Zeile „Failed: TypeError: …“ für einen fehlgeschlagenen Tool-Call, die sich zu denselben Frames öffnet.

  1. HextaUI Pro holen

    Eine einmalige Zahlung schaltet jeden Block frei, auch künftige. Preise ansehen.

  2. Die Pro-Registry zu components.json hinzufügen

    components.json
    {
      "registries": {
        "@hextaui-pro": {
          "url": "https://hextaui.com/r/pro/{name}.json",
          "headers": {
            "Authorization": "Bearer ${HEXTAUI_PRO_TOKEN}"
          }
        }
      }
    }
  3. Token hinzufügen

    Erstelle auf deiner Kontoseite einen Token und trage ihn in .env.local als HEXTAUI_PRO_TOKEN ein.

  4. Den Block hinzufügen

    pnpm dlx shadcn@latest add @hextaui-pro/stack-trace

Aus einem Log

Übergib den rohen Text aus einem Terminal, einem Log oder einem Tool-Ergebnis. getEditorHref macht aus Frames vscode://- oder cursor://-Links, und Ask to fix gibt dir den geparsten Fehler, um ihn an den Agenten zurückzuschicken.

"use client"

import { getEditorHref } from "@/components/blocks/stack-trace/parse-stack-trace"
import { StackTrace } from "@/components/blocks/stack-trace/stack-trace"

export function CrashReport({
  log,
  onAsk,
}: {
  log: string
  onAsk: (prompt: string) => void
}) {
  return (
    <StackTrace
      trace={log}
      getFrameHref={(frame) =>
        frame.kind === "app"
          ? getEditorHref(frame, { editor: "cursor", root: "/Users/me/acme" })
          : undefined
      }
      onAskToFix={(error) =>
        onAsk(`Fix this ${error.type}: ${error.message}\n\n${error.raw}`)
      }
    />
  )
}

Mit dem AI SDK

Ein Tool, das einen Fehler wirft, endet im Zustand output-error mit errorText. Zeige ihn als kompakten StackTrace im fehlgeschlagenen ToolCall, damit der Schritt eine einzige Zeile bleibt, bis ihn jemand öffnet.

"use client"

import { useChat } from "@ai-sdk/react"
import {
  getToolName,
  isToolUIPart,
  type DynamicToolUIPart,
  type ToolUIPart,
  type UIMessage,
} from "ai"

import type { ToolCallProps } from "../tool-calls/tool-call"
import { ToolCalls } from "../tool-calls/tool-group"
import { getToolPartStatus } from "../tool-calls/tool-part"
import { getEditorHref } from "@/components/blocks/stack-trace/parse-stack-trace"
import { StackTrace } from "@/components/blocks/stack-trace/stack-trace"

type ToolPart = ToolUIPart | DynamicToolUIPart

function toCall(
  part: ToolPart,
  streaming: boolean,
  onAsk: (text: string) => void
): ToolCallProps {
  const input = (part.input ?? {}) as { command?: string }
  const failed = part.state === "output-error"
  return {
    id: part.toolCallId,
    kind: getToolName(part) === "runCommand" ? "run" : "other",
    name: getToolName(part),
    subject: input.command,
    status: getToolPartStatus(part, { stopped: !streaming }),
    defaultOpen: failed ? true : undefined,
    content: failed ? (
      <StackTrace
        variant="compact"
        trace={part.errorText}
        getFrameHref={(frame) =>
          getEditorHref(frame, { root: process.env.NEXT_PUBLIC_PROJECT_ROOT })
        }
        onAskToFix={(error) =>
          onAsk(
            `The ${getToolName(part)} call failed with ${error.type}: ${error.message}. Fix it.`
          )
        }
      />
    ) : undefined,
  }
}

function AssistantMessage({
  message,
  streaming,
  onAsk,
}: {
  message: UIMessage
  streaming: boolean
  onAsk: (text: string) => void
}) {
  const calls = message.parts
    .filter(isToolUIPart)
    .map((part) => toCall(part, streaming, onAsk))
  return calls.length ? <ToolCalls calls={calls} /> : null
}

export function Chat() {
  const { messages, status, sendMessage } = useChat()
  const busy = status === "submitted" || status === "streaming"

  return messages.map((message, index) =>
    message.role === "assistant" ? (
      <AssistantMessage
        key={message.id}
        message={message}
        streaming={busy && index === messages.length - 1}
        onAsk={(text) => sendMessage({ text })}
      />
    ) : null
  )
}

In einer Next.js Error Boundary

parseError liest ein Error-Objekt samt Name, Nachricht und Ursachenkette. Zeige den Trace in der Entwicklung und eine schlichte Nachricht in Produktion.

"use client"

import { Button } from "@/components/ui/button"

import { parseError } from "@/components/blocks/stack-trace/parse-stack-trace"
import { StackTrace } from "@/components/blocks/stack-trace/stack-trace"

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <main className="mx-auto flex w-full max-w-2xl flex-col gap-4 p-6">
      {process.env.NODE_ENV === "development" ? (
        <StackTrace label="Crashed" trace={parseError(error)} />
      ) : (
        <p className="text-sm text-muted-foreground">Something went wrong.</p>
      )}
      <Button variant="outline" className="self-start" onClick={reset}>
        Try again
      </Button>
    </main>
  )
}

Nur die Frames

parseStackTrace und StackFrames funktionieren auch allein, etwa um unter jedem fehlgeschlagenen Test einen kurzen Stack zu zeigen.

"use client"

import { parseStackTrace } from "@/components/blocks/stack-trace/parse-stack-trace"
import { StackFrames } from "@/components/blocks/stack-trace/stack-frames"

export function FailedTest({ name, stack }: { name: string; stack: string }) {
  const error = parseStackTrace(stack, { root: "/Users/me/acme" })

  return (
    <div className="flex flex-col gap-1">
      <p className="text-sm">
        {name}: <span className="text-muted-foreground">{error.message}</span>
      </p>
      <StackFrames frames={error.frames} showSource={false} />
    </div>
  )
}

Aufbau

Die Teile, die du zusammensetzt, von außen nach innen.

PartBeschreibung
StackTraceDer Fehler: Typ, Nachricht, Aktionen, Frames und Ursachen. Standard ist eine Card; compact ist eine Zeile, die sich aufklappt.
StackFramesDie Frame-Liste für sich, mit eingeklappten Framework-Frames und dem Quellausschnitt.
parseStackTrace, parseErrorReine Parser, die Text oder ein Error-Objekt in einen ParsedStackTrace umwandeln.
getEditorHrefErzeugt einen vscode://-, cursor://-, windsurf://- oder zed://-Link für einen Frame.

StackTrace

Akzeptiert außerdem alle div-Props außer children.

PropTypStandard
traceDer rohe Stack-Text oder ein Trace, den du selbst geparst und angereichert hast.
string | ParsedStackTrace–
variantcompact rendert eine Zeile „Failed: …“, die sich zu den Frames öffnet, zur Verwendung in einem ToolCall.
"default" | "compact""default"
labelDas Statuswort vor dem Fehlertyp, etwa „Crashed“ oder „Test failed“.
string"Failed"
rootProjektwurzel, die von absoluten Pfaden entfernt wird. Ohne Angabe wird sie über node_modules oder .venv ermittelt.
string–
getFrameHrefMacht aus einem Frame einen Link, etwa mit getEditorHref.
(frame: StackFrame) => string | undefined–
onFrameClickWird aufgerufen, wenn ein Frame angeklickt wird. Rufe event.preventDefault() auf, um Links selbst zu behandeln.
(frame: StackFrame, event: MouseEvent) => void–
onAskToFixZeigt Ask to fix an und erhält den geparsten Fehler.
(trace: ParsedStackTrace) => void–
askLabelBeschriftung des Buttons Ask to fix.
string"Ask to fix"
showSourceZeigt Quellzeilen unter den Frames und den Ausschnitt für deinen obersten Frame.
booleantrue
foldFaltet Folgen von zwei oder mehr Framework- oder internen Frames zusammen.
booleantrue
messageLinesZeilen der Nachricht, die vor Show more angezeigt werden.
number3
openGesteuerter Offen-Zustand der kompakten Variante.
boolean–
defaultOpenOb die kompakte Variante geöffnet startet.
booleanfalse
onOpenChangeWird aufgerufen, wenn die kompakte Variante auf- oder zugeklappt wird.
(open: boolean) => void–

StackFrames

Akzeptiert außerdem alle ol-Props außer children.

PropTypStandard
framesFrames aus parseStackTrace, der innerste zuerst.
StackFrame[]–
foldFaltet Folgen von Frames außerhalb deiner App zusammen.
booleantrue
showSourceZeigt Quellzeilen und den Ausschnitt des obersten Frames.
booleantrue
getFrameHrefMacht aus einem Frame einen Link.
(frame: StackFrame) => string | undefined–
onFrameClickWird aufgerufen, wenn ein Frame angeklickt wird.
(frame: StackFrame, event: MouseEvent) => void–

parseStackTrace(text, options)

Gibt einen ParsedStackTrace zurück. parseError(error, options) macht dasselbe für ein Error-Objekt und seine Ursache.

PropTypStandard
textEin Stack, ein Traceback oder rohe Log-Ausgabe drumherum.
string–
options.rootProjektwurzel, die von absoluten Pfaden entfernt wird.
string–
options.classifyÜberschreibt die Art eines Frames, etwa um einen vendored Ordner als Framework-Code zu behandeln.
(frame: StackFrame) => StackFrameKind | undefined–
PropTypStandard
typeFehlertyp, etwa TypeError oder billing.plans.PlanNotFound.
string–
messageDie Nachricht, die über mehrere Zeilen gehen kann.
string–
framesIn jeder Sprache der innerste zuerst, also ist frames[0] die Stelle, an der der Fehler geworfen wurde.
StackFrame[]–
rawDer Originaltext, den Copy verwendet.
string–
languageWelches Format geparst wurde.
"javascript" | "python"–
codeFehlercode, etwa ERR_MODULE_NOT_FOUND oder ECONNREFUSED.
string–
detailsZusätzliche Eigenschaften, die Node nach den Frames ausgibt, etwa errno und syscall.
string–
preambleLog-Zeilen, die vor dem Fehler kamen.
string–
causeDer nächste Fehler in der Kette, mit relation auf cause oder context gesetzt.
ParsedStackTrace–
PropTypStandard
kindDein Code, eine Abhängigkeit oder die Runtime selbst.
"app" | "framework" | "internal"–
fnFunktionsname. Undefined bei anonymen Funktionen, die nur ihren Ort zeigen.
string–
fileLesbarer Pfad relativ zum Projekt, etwa app/api/users/route.ts.
string–
pathDer Ort wie gemeldet, ohne file://- und webpack-Präfixe. Absolut, wenn der Stack einen absoluten Pfad hatte.
string–
line, columnPosition in der Datei.
number–
packagePaket, zu dem ein Frame außerhalb der App gehört, etwa next oder fastapi.
string–
source, sourceStartQuellzeilen und die Nummer der ersten. Mehrere Zeilen erscheinen als Ausschnitt.
string, number–
rawDie Originalzeile. Zeilen, die der Parser nicht erkennt, haben nur raw.
string–

getEditorHref(frame, options)

Gibt undefined für Frames ohne Datei auf der Festplatte zurück.

PropTypStandard
options.editorDas zu verwendende URL-Schema.
"vscode" | "cursor" | "windsurf" | "zed""vscode"
options.rootWird mit relativen Pfaden verbunden, etwa aus webpack-internal-Frames.
string–
TasteAktion
TabWechselt durch die Aktionen, Show more, Frame-Links und zusammengefaltete Frame-Zeilen.
EnterSpaceÖffnet oder schließt zusammengefaltete Frames oder die kompakte Zeile.
EnterÖffnet einen Frame-Link in deinem Editor.
  • Frames sind eine geordnete Liste, sodass Screenreader ansagen, wie viele es gibt und an welcher Stelle jeder steht.
  • Zusammengefaltete Zeilen sind Buttons mit aria-expanded, und eingeklappte Frames bleiben über die Seitensuche des Browsers auffindbar, die die Faltung öffnet.
  • Die Standardansicht ist eine Gruppe, benannt nach Status und Fehlertyp, und jede Ursache ist ein Abschnitt namens „Caused by …“.
  • Status ist nie nur Farbe: Der Fehler steht als Text neben seinem Icon, und Copy sagt „Copied“ an.

Gebaut mit

Die kostenlosen HextaUI-Komponenten, aus denen Stack Trace besteht. Jede lässt sich einzeln installieren.

Code

4 Dateien, hinzugefügt zu components/blocks/stack-trace.