Stack Trace

Mostre uma falha do jeito que um desenvolvedor lê. Seu código primeiro, frames do framework recolhidos, a linha que falhou em contexto e cada causa em ordem. Lê stacks de Node, Chrome, Firefox, Safari, Bun, Deno e Python, com copiar, abrir no editor e pedir para corrigir.

Quando um comando, uma chamada de ferramenta ou um teste de um agente falha, a parte útil do erro fica enterrada em cinquenta linhas de código interno do framework. O Stack Trace coloca o tipo e a mensagem do erro primeiro, mostra seus próprios frames em contraste total com arquivo, linha e coluna, e recolhe cada sequência de frames do framework em uma linha discreta como “8 framework frames · next”.

parseStackTrace lê stacks V8 do Node, Chrome, Bun e Deno, stacks do Firefox e do Safari, frames do Vitest com o código abaixo deles e tracebacks do Python, incluindo causas encadeadas de [cause], Caused by: e das seções “direct cause” e “during handling” do Python. Classifica node_modules, node:internal, o código interno do Next.js, site-packages e a biblioteca padrão como código fora do app, e transforma caminhos file:// e webpack-internal em caminhos legíveis do projeto. Linhas que ele não reconhece são mantidas, nunca descartadas.

O frame onde seu código falhou pode mostrar o código com a linha que falhou destacada, usando o Code Block. Mensagens longas são cortadas com Show more, Copy devolve o texto original e os frames abrem no seu editor com getFrameHref ou onFrameClick. A variante compacta é uma única linha “Failed: TypeError: …” para uma chamada de ferramenta que falhou, que se abre nos mesmos frames.

  1. Obtenha o HextaUI Pro

    Um único pagamento libera todos os blocos, incluindo os futuros. Ver preços.

  2. Adicione o registro Pro ao components.json

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

    Crie um token na sua página de conta e coloque-o em .env.local como HEXTAUI_PRO_TOKEN.

  4. Adicione o bloco

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

A partir de um log

Passe o texto bruto de um terminal, de um log ou do resultado de uma ferramenta. getEditorHref transforma frames em links vscode:// ou cursor://, e Ask to fix entrega o erro analisado para você enviar de volta ao 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}`)
      }
    />
  )
}

Com o AI SDK

Uma ferramenta que lança um erro termina no estado output-error com errorText. Mostre-o como um StackTrace compacto dentro do ToolCall que falhou, para que a etapa fique em uma linha até alguém abri-la.

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

Em um error boundary do Next.js

parseError lê um objeto Error, incluindo nome, mensagem e cadeia de causas. Mostre o trace em desenvolvimento e uma mensagem simples em produção.

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

Só os frames

parseStackTrace e StackFrames funcionam sozinhos, por exemplo para mostrar uma stack curta abaixo de cada teste que falhou.

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

Anatomia

As partes que você compõe, de fora para dentro.

ParteDescrição
StackTraceO erro: tipo, mensagem, ações, frames e causas. O padrão é um card; compact é uma linha que se expande.
StackFramesA lista de frames sozinha, com frames do framework recolhidos e o trecho de código.
parseStackTrace, parseErrorParsers puros que transformam texto ou um objeto Error em um ParsedStackTrace.
getEditorHrefCria um link vscode://, cursor://, windsurf:// ou zed:// para um frame.

StackTrace

Também aceita todas as props de div, exceto children.

PropTipoPadrão
traceO texto bruto da stack, ou um trace que você analisou e enriqueceu.
string | ParsedStackTrace–
variantcompact mostra uma linha “Failed: …” que se abre nos frames, para usar dentro de um ToolCall.
"default" | "compact""default"
labelA palavra de status antes do tipo de erro, como “Crashed” ou “Test failed”.
string"Failed"
rootRaiz do projeto, removida dos caminhos absolutos. Se omitida, é deduzida de node_modules ou .venv.
string–
getFrameHrefTransforma um frame em link, por exemplo com getEditorHref.
(frame: StackFrame) => string | undefined–
onFrameClickChamado quando um frame é clicado. Chame event.preventDefault() para tratar os links você mesmo.
(frame: StackFrame, event: MouseEvent) => void–
onAskToFixMostra Ask to fix e recebe o erro analisado.
(trace: ParsedStackTrace) => void–
askLabelRótulo do botão Ask to fix.
string"Ask to fix"
showSourceMostra linhas de código abaixo dos frames e o trecho do seu frame do topo.
booleantrue
foldRecolhe sequências de dois ou mais frames do framework ou internos.
booleantrue
messageLinesLinhas da mensagem exibidas antes de Show more.
number3
openEstado aberto controlado da variante compacta.
boolean–
defaultOpenSe a variante compacta começa aberta.
booleanfalse
onOpenChangeChamado quando a variante compacta abre ou fecha.
(open: boolean) => void–

StackFrames

Também aceita todas as props de ol, exceto children.

PropTipoPadrão
framesFrames de parseStackTrace, o mais interno primeiro.
StackFrame[]–
foldRecolhe sequências de frames que não são do app.
booleantrue
showSourceMostra linhas de código e o trecho do frame do topo.
booleantrue
getFrameHrefTransforma um frame em link.
(frame: StackFrame) => string | undefined–
onFrameClickChamado quando um frame é clicado.
(frame: StackFrame, event: MouseEvent) => void–

parseStackTrace(text, options)

Retorna um ParsedStackTrace. parseError(error, options) faz o mesmo para um objeto Error e sua causa.

PropTipoPadrão
textUma stack, um traceback ou a saída de log bruta em volta dele.
string–
options.rootRaiz do projeto a remover dos caminhos absolutos.
string–
options.classifySubstitui o tipo de um frame, por exemplo para tratar uma pasta vendored como código de framework.
(frame: StackFrame) => StackFrameKind | undefined–
PropTipoPadrão
typeTipo do erro, como TypeError ou billing.plans.PlanNotFound.
string–
messageA mensagem, que pode ocupar várias linhas.
string–
framesO mais interno primeiro em todas as linguagens, então frames[0] é onde o erro foi lançado.
StackFrame[]–
rawO texto original, usado por Copy.
string–
languageQual formato foi analisado.
"javascript" | "python"–
codeCódigo do erro, como ERR_MODULE_NOT_FOUND ou ECONNREFUSED.
string–
detailsPropriedades extras que o Node imprime depois dos frames, como errno e syscall.
string–
preambleLinhas de log que vieram antes do erro.
string–
causeO próximo erro da cadeia, com relation definido como cause ou context.
ParsedStackTrace–
PropTipoPadrão
kindSeu código, uma dependência ou o próprio runtime.
"app" | "framework" | "internal"–
fnNome da função. Undefined para funções anônimas, que mostram só a localização.
string–
fileCaminho legível relativo ao projeto, como app/api/users/route.ts.
string–
pathO local como foi informado, sem os prefixos file:// e webpack. Absoluto quando a stack tinha um.
string–
line, columnPosição no arquivo.
number–
packagePacote ao qual pertence um frame que não é do app, como next ou fastapi.
string–
source, sourceStartLinhas de código e o número da primeira. Várias linhas aparecem como trecho.
string, number–
rawA linha original. Linhas que o parser não reconhece só têm raw.
string–

getEditorHref(frame, options)

Retorna undefined para frames sem arquivo no disco.

PropTipoPadrão
options.editorO esquema de URL a usar.
"vscode" | "cursor" | "windsurf" | "zed""vscode"
options.rootUnido a caminhos relativos, como os de frames webpack-internal.
string–
TeclaAção
TabPercorre as ações, Show more, os links de frames e as linhas de frames recolhidos.
EnterSpaceAbre ou fecha frames recolhidos ou a linha compacta.
EnterAbre o link de um frame no seu editor.
  • Os frames são uma lista ordenada, então os leitores de tela anunciam quantos são e a posição de cada um.
  • As linhas recolhidas são botões com aria-expanded, e os frames recolhidos continuam encontráveis pela busca na página do navegador, que abre o grupo.
  • A visualização padrão é um grupo nomeado pelo status e pelo tipo de erro, e cada causa é uma seção chamada “Caused by …”.
  • O status nunca depende só da cor: a falha aparece escrita ao lado do ícone, e Copy anuncia “Copied”.

Construído com

Os componentes gratuitos do HextaUI de que Stack Trace é feito. Cada um é instalado separadamente.

Código

4 arquivos, adicionados a components/blocks/stack-trace.