Stack Trace

Muestra un error como lo lee un desarrollador. Tu código primero, los frames del framework plegados, la línea que falla en contexto y cada causa en orden. Analiza stacks de Node, Chrome, Firefox, Safari, Bun, Deno y Python, con copiar, abrir en el editor y pedir que lo arregle.

Cuando falla un comando, una llamada a herramienta o un test de un agente, la parte útil del error queda enterrada en cincuenta líneas de código interno del framework. Stack Trace pone primero el tipo de error y el mensaje, muestra tus propios frames con pleno contraste junto con archivo, línea y columna, y pliega cada secuencia de frames del framework en una fila discreta como “8 framework frames · next”.

parseStackTrace lee stacks V8 de Node, Chrome, Bun y Deno, stacks de Firefox y Safari, frames de Vitest con el código que llevan debajo y tracebacks de Python, incluidas las causas encadenadas de [cause], Caused by: y las secciones “direct cause” y “during handling” de Python. Clasifica node_modules, node:internal, el código interno de Next.js, site-packages y la biblioteca estándar como código ajeno a la app, y convierte las rutas file:// y webpack-internal en rutas legibles del proyecto. Las líneas que no reconoce se conservan, nunca se descartan.

El frame donde falló tu código puede mostrar su código con la línea que falla resaltada, usando Code Block. Los mensajes largos se recortan con Show more, Copy devuelve el texto original y los frames se abren en tu editor con getFrameHref u onFrameClick. La variante compacta es una sola línea “Failed: TypeError: …” para una llamada a herramienta fallida que se abre en los mismos frames.

  1. Obtén HextaUI Pro

    Un solo pago desbloquea todos los bloques, incluidos los futuros. Ver precios.

  2. Añade el registro Pro a components.json

    components.json
    {
      "registries": {
        "@hextaui-pro": {
          "url": "https://hextaui.com/r/pro/{name}.json",
          "headers": {
            "Authorization": "Bearer ${HEXTAUI_PRO_TOKEN}"
          }
        }
      }
    }
  3. Añade tu token

    Crea un token en tu página de cuenta y colócalo en .env.local como HEXTAUI_PRO_TOKEN.

  4. Añade el bloque

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

Desde un log

Pasa el texto en bruto de una terminal, un log o el resultado de una herramienta. getEditorHref convierte los frames en enlaces vscode:// o cursor://, y Ask to fix te entrega el error analizado para enviarlo de vuelta al agente.

"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}`)
      }
    />
  )
}

Con AI SDK

Una herramienta que lanza un error termina en el estado output-error con errorText. Muéstralo como un StackTrace compacto dentro del ToolCall fallido, para que el paso sea una sola línea hasta que alguien lo abra.

"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
  )
}

En un error boundary de Next.js

parseError lee un objeto Error, con su nombre, mensaje y cadena de causas. Muestra la traza en desarrollo y un mensaje sencillo en producción.

"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>
  )
}

Solo los frames

parseStackTrace y StackFrames funcionan por separado, por ejemplo para mostrar un stack corto bajo cada test fallido.

"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>
  )
}

Anatomía

Las partes que compones, de fuera hacia dentro.

ParteDescripción
StackTraceEl error: tipo, mensaje, acciones, frames y causas. Por defecto es una card; compact es una línea que se expande.
StackFramesLa lista de frames por sí sola, con los frames del framework plegados y el fragmento de código.
parseStackTrace, parseErrorParsers puros que convierten texto o un objeto Error en un ParsedStackTrace.
getEditorHrefCrea un enlace vscode://, cursor://, windsurf:// o zed:// para un frame.

StackTrace

También acepta todas las props de div excepto children.

PropTipoPredeterminado
traceEl texto del stack en bruto, o una traza que analizaste y enriqueciste tú mismo.
string | ParsedStackTrace–
variantcompact muestra una línea “Failed: …” que se abre en los frames, para usar dentro de un ToolCall.
"default" | "compact""default"
labelLa palabra de estado antes del tipo de error, como “Crashed” o “Test failed”.
string"Failed"
rootRaíz del proyecto, que se quita de las rutas absolutas. Si se omite, se deduce de node_modules o .venv.
string–
getFrameHrefConvierte un frame en un enlace, por ejemplo con getEditorHref.
(frame: StackFrame) => string | undefined–
onFrameClickSe llama al hacer clic en un frame. Llama a event.preventDefault() para gestionar los enlaces tú mismo.
(frame: StackFrame, event: MouseEvent) => void–
onAskToFixMuestra Ask to fix y recibe el error analizado.
(trace: ParsedStackTrace) => void–
askLabelTexto del botón Ask to fix.
string"Ask to fix"
showSourceMuestra las líneas de código bajo los frames y el fragmento de tu frame superior.
booleantrue
foldPliega secuencias de dos o más frames del framework o internos.
booleantrue
messageLinesLíneas del mensaje que se muestran antes de Show more.
number3
openEstado abierto controlado de la variante compacta.
boolean–
defaultOpenSi la variante compacta empieza abierta.
booleanfalse
onOpenChangeSe llama cuando la variante compacta se abre o se cierra.
(open: boolean) => void–

StackFrames

También acepta todas las props de ol excepto children.

PropTipoPredeterminado
framesFrames de parseStackTrace, el más interno primero.
StackFrame[]–
foldPliega las secuencias de frames que no son de tu app.
booleantrue
showSourceMuestra las líneas de código y el fragmento del frame superior.
booleantrue
getFrameHrefConvierte un frame en un enlace.
(frame: StackFrame) => string | undefined–
onFrameClickSe llama al hacer clic en un frame.
(frame: StackFrame, event: MouseEvent) => void–

parseStackTrace(text, options)

Devuelve un ParsedStackTrace. parseError(error, options) hace lo mismo con un objeto Error y su causa.

PropTipoPredeterminado
textUn stack, un traceback o la salida de log en bruto que lo rodea.
string–
options.rootRaíz del proyecto que se quita de las rutas absolutas.
string–
options.classifyCambia el tipo de un frame, por ejemplo para tratar una carpeta vendored como código del framework.
(frame: StackFrame) => StackFrameKind | undefined–
PropTipoPredeterminado
typeTipo de error, como TypeError o billing.plans.PlanNotFound.
string–
messageEl mensaje, que puede ocupar varias líneas.
string–
framesEl más interno primero en todos los lenguajes, así que frames[0] es donde se lanzó.
StackFrame[]–
rawEl texto original, que usa Copy.
string–
languageQué formato se analizó.
"javascript" | "python"–
codeCódigo de error, como ERR_MODULE_NOT_FOUND o ECONNREFUSED.
string–
detailsPropiedades extra que Node imprime después de los frames, como errno y syscall.
string–
preambleLíneas de log que aparecieron antes del error.
string–
causeEl siguiente error de la cadena, con relation en cause o context.
ParsedStackTrace–
PropTipoPredeterminado
kindTu código, una dependencia o el propio runtime.
"app" | "framework" | "internal"–
fnNombre de la función. Undefined en funciones anónimas, que muestran solo su ubicación.
string–
fileRuta legible relativa al proyecto, como app/api/users/route.ts.
string–
pathLa ubicación tal como se informó, sin los prefijos file:// y webpack. Absoluta cuando el stack tenía una.
string–
line, columnPosición en el archivo.
number–
packagePaquete al que pertenece un frame que no es de la app, como next o fastapi.
string–
source, sourceStartLíneas de código y el número de la primera. Varias líneas se muestran como fragmento.
string, number–
rawLa línea original. Las líneas que el parser no reconoce solo tienen raw.
string–

getEditorHref(frame, options)

Devuelve undefined para frames sin archivo en disco.

PropTipoPredeterminado
options.editorEl esquema de URL que se usa.
"vscode" | "cursor" | "windsurf" | "zed""vscode"
options.rootSe une a las rutas relativas, como las de los frames webpack-internal.
string–
KeyAcción
TabRecorre las acciones, Show more, los enlaces de frames y las filas de frames plegados.
EnterSpaceAbre o cierra los frames plegados o la línea compacta.
EnterAbre el enlace de un frame en tu editor.
  • Los frames son una lista ordenada, así que los lectores de pantalla anuncian cuántos hay y la posición de cada uno.
  • Las filas plegadas son botones con aria-expanded, y los frames plegados se pueden encontrar con la búsqueda en la página del navegador, que abre el pliegue.
  • La vista por defecto es un grupo con el nombre de su estado y tipo de error, y cada causa es una sección llamada “Caused by …”.
  • El estado nunca depende solo del color: el fallo aparece escrito junto a su icono, y Copy anuncia “Copied”.

Construido con

Los componentes gratuitos de HextaUI con los que está hecho Stack Trace. Cada uno se instala por separado.

Código

4 archivos, añadidos a components/blocks/stack-trace.