Tipos de erro em JavaScript e como ler o console
Os sete erros nativos da linguagem, o que cada mensagem quer dizer e como ler uma stack trace de cima para baixo — com cada erro reproduzido no Node 24.
Todo erro em JavaScript é um objeto com três informações: name (a família do
erro), message (a descrição) e stack (o caminho de chamadas até o ponto da
falha). Aprender a ler essas três coisas é o que separa “deu erro, não sei o que
é” de “quebrou na linha 42 porque a API não devolveu entrega”.
A resposta curta: existem sete tipos nativos, e na prática você vai
encontrar quatro deles. SyntaxError acontece antes de o arquivo rodar,
ReferenceError é nome que não existe, TypeError é valor que não serve para o
que você pediu e RangeError é número ou recursão fora do limite. O resto deste
texto mostra cada um rodando, e ensina a ler a stack trace que vem junto.
Os exemplos são de uma loja virtual: pedido, frete, cupom, gateway de pagamento.
Leia o erro como uma ficha de atendimento
Quando um aparelho vai para assistência, a ficha separa o tipo do defeito, a
descrição e o caminho percorrido até a bancada. Um erro JavaScript entrega as
mesmas pistas: name classifica a família, message descreve o que falhou e
stack lista as chamadas que trouxeram o programa até ali.
Essa comparação não quer dizer que a mensagem já conhece a causa. Ela informa o sintoma no ponto da quebra. Cabe a você voltar pelo caminho e descobrir quem entregou o valor errado. Antes de ler cada exemplo, faça um treino de dez segundos: encontre o nome, sublinhe o valor citado na mensagem e localize o primeiro arquivo seu na stack. Só depois olhe o código. Esse roteiro transforma um paredão vermelho em três perguntas pequenas e evita começar a depuração pela última linha aleatória do console.
Os sete nomes que a linguagem usa
Todos herdam de Error, e é por isso que erro instanceof Error pega qualquer
um deles:
const nativos = [
EvalError, RangeError, ReferenceError,
SyntaxError, TypeError, URIError, AggregateError,
];
for (const Tipo of nativos) {
const instancia = Tipo === AggregateError ? new Tipo([], 'x') : new Tipo('x');
console.log(
Tipo.name.padEnd(16),
'herda de Error:', instancia instanceof Error,
'| protótipo:', Object.getPrototypeOf(Tipo.prototype).constructor.name,
);
}| tipo | quando aparece | frequência real |
|---|---|---|
SyntaxError |
o motor não conseguiu entender o arquivo, ou o JSON.parse recebeu texto quebrado |
altíssima |
ReferenceError |
você usou um nome que não existe em nenhum escopo visível | alta |
TypeError |
o valor existe mas não serve: null.x, undefined.y, x is not a function |
altíssima |
RangeError |
número fora do intervalo aceito, array de tamanho inválido, recursão infinita | média |
URIError |
decodeURIComponent ou encodeURI receberam uma sequência de escape malformada |
baixa |
AggregateError |
vários erros de uma vez — na prática, só o Promise.any produz |
baixa |
EvalError |
nunca, em código moderno: sobrou por compatibilidade com o eval antigo |
zero |
Quatro deles em uma tacada só, cada um provocado de propósito:
const tentativas = [
() => cupomDeDesconto,
() => null.total,
() => (289.9).toFixed(105),
() => decodeURIComponent('%BR'),
() => JSON.parse('{"total": }'),
];
for (const executar of tentativas) {
try {
executar();
} catch (erro) {
console.log(erro.name.padEnd(15), '|', erro.message);
}
}O último merece um comentário: JSON.parse lança SyntaxError em tempo de
execução, e por isso ele pode ser capturado por um
try/catch. O SyntaxError do próximo tópico é
outra história.
O erro que acontece antes de rodar
SyntaxError de arquivo não é capturável e não deixa nem a primeira linha
executar. O motor precisa entender o arquivo inteiro antes de rodar qualquer
coisa dele:
console.log('primeira linha');
const carrinho = { itens: ['Teclado mecânico'];Repare no que não apareceu: a linha primeira linha. Se você espera um log
no começo do arquivo e ele some, essa é a pista de que o problema é sintático, e
não lógico.
O Unexpected token ';' aqui é enganoso: o ponto e vírgula está certo, o que
falta é o } que deveria vir antes dele. O motor reclama do primeiro caractere
que não cabe na gramática, não do lugar onde você errou — quase sempre a chave,
o parêntese ou a aspa esquecida está antes do cursor ^.
Unexpected end of input
O primo desse erro é o mais frustrante de todos, porque a linha apontada é sempre a última do arquivo — que costuma estar impecável:
function calcularTotal(itens) {
let total = 0;
for (const item of itens) {
total += item.preco * item.quantidade;
}
return total;
console.log(calcularTotal([{ preco: 289.9, quantidade: 1 }]));Traduzindo: “o arquivo acabou e eu ainda estava esperando alguma coisa”. Falta
o } que fecha calcularTotal. O motor só descobre isso no fim, porque até lá
o console.log da linha 8 era um candidato perfeitamente válido a corpo de
função.
Como caçar: pelo recuo. Salve o arquivo com o formatador ligado (Prettier no salvar) e o bloco que não fecha vai se denunciar sozinho, empurrando o resto do código para a direita.
Nome que não existe contra valor que não serve
Essa dupla responde por boa parte dos erros do dia a dia, e a diferença entre elas é o primeiro diagnóstico a fazer:
const carrinho = { cliente: 'Ana' };
console.log('propriedade que não existe:', carrinho.cupom);
console.log('typeof em nome inexistente:', typeof cupomGlobal);
try {
console.log(cupomGlobal);
} catch (erro) {
console.log(erro.name, '|', erro.message);
}
try {
carrinho.cupom.codigo;
} catch (erro) {
console.log(erro.name, '|', erro.message);
}Quatro fatos numa saída só. Pedir uma propriedade que não existe devolve
undefined sem reclamar. Pedir uma variável que não existe lança
ReferenceError — exceto dentro de typeof, o único operador que aceita nome
inexistente sem explodir. E quando você encadeia mais um ponto depois de um
undefined, o erro muda de família: vira TypeError, a mensagem mais comum de
toda a linguagem, detalhada em
TypeError: Cannot read properties of undefined.
Anatomia de uma stack trace
A stack trace é o histórico de quem chamou quem até o ponto da falha. Este exemplo tem três níveis de propósito:
function calcularFrete(pedido) {
return pedido.entrega.cep;
}
function montarResumo(pedido) {
return `frete para ${calcularFrete(pedido)}`;
}
console.log(montarResumo({ cliente: 'Ana', itens: 2 }));Leia por partes:
- Cabeçalho — arquivo, linha, o próprio código e o
^na coluna exata. No DevTools esse trecho não aparece; ele é um extra do Node. name: message—TypeError: Cannot read properties of undefined (reading 'cep'). O(reading 'cep')diz qual propriedade você tentou ler; o que estavaundefinedé o que vem antes dela,pedido.entrega.- Primeiro
at— onde quebrou:calcularFrete, linha 2, coluna 25. atseguintes — quem chamou, em ordem inversa.montarResumochamoucalcularFrete; a linha 9 do módulo chamoumontarResumo.- Quadros de
node:internal/— encanamento do Node. No navegador, o equivalente são os quadros de biblioteca (react-dom,vue). Ignore.
O truque de leitura é este: desça a stack até o primeiro at que aponta para
um arquivo seu e não é onde o erro estourou. No exemplo, é a linha 9 — e é
justamente lá, no objeto sem entrega, que está a causa. O topo diz onde doeu;
a descida diz onde nasceu.
Quando a stack fica longa demais, dá para cortá-la:
Error.stackTraceLimit = 3;
function nivel3() { throw new Error('estoque não encontrado'); }
function nivel2() { return nivel3(); }
function nivel1() { return nivel2(); }
try { nivel1(); } catch (erro) { console.log(erro.stack); }O padrão do V8 é 10 quadros. Em log de produção com muita camada, subir esse
número (Error.stackTraceLimit = 30) revela a origem que estava sendo cortada.
RangeError: quando o número ou a pilha estoura
O RangeError mais visto não vem de número nenhum — vem de recursão sem parada:
function totalComBrindes(valor) {
return totalComBrindes(valor + 1);
}
console.log(totalComBrindes(0));A assinatura é inconfundível: a mesma função repetida linha após linha. O Node imprimiu dez quadros porque esse é o padrão do V8 — a recursão real passou de dez mil chamadas antes de estourar. Quando isso aparece, procure o caso-base que falta — ou, em componente de interface, o efeito que atualiza o estado que dispara o mesmo efeito.
Erro silencioso: quando nada é lançado
O erro mais caro não é o que aparece em vermelho. É o que não aparece:
const itens = [
{ nome: 'Teclado mecânico', preco: '289,90' },
{ nome: 'Mouse sem fio', preco: '149.90' },
];
const total = itens.reduce((soma, item) => soma + parseFloat(item.preco), 0);
console.log('total :', total);
console.log('formato:', total.toFixed(2));
console.log('quarto item:', itens[3]);
console.log('soma com string:', 10 + '5');Nenhum erro, e o total está errado. parseFloat('289,90') para na vírgula e
devolve 289 — o preço perdeu noventa centavos e o cliente pagou a menos. Índice
fora do array devolve undefined em vez de estourar, e 10 + '5' concatena em
vez de somar.
Esses três comportamentos são a razão de o JavaScript ter fama de traiçoeiro: a
linguagem prefere seguir adiante com um valor esquisito a interromper. É por
isso que validar dado que vem de fora — API, formulário, localStorage — é
trabalho seu, não do motor.
Por que a stack aponta para uma linha que não existe
Em produção o seu código passa por um bundler e vira uma linha só. A stack continua real, mas inútil:
function c(p){return p.entrega.cep}function m(p){return "frete para "+c(p)}console.log(m({cliente:"Ana"}));at c (bundle.min.js:1:32) é tecnicamente correto e humanamente inútil:
calcularFrete virou c, montarResumo virou m, e tudo mora na linha 1.
O source map é o arquivo que desfaz isso. Ele mapeia cada posição do bundle
de volta para o arquivo, a linha e o nome originais. Com ele ativo, o DevTools
mostra calcularFrete (pedido.js:2:25) no lugar de c (bundle.min.js:1:32).
Três coisas para conferir quando a stack sai minificada:
- O build de desenvolvimento gera source map? Em Vite é o padrão; em produção,
build.sourcemap: true. - O
.mapestá sendo servido? A última linha do bundle deve ter o comentário//# sourceMappingURL=, e a requisição do.mapnão pode voltar 404. - O DevTools está com Settings → Preferences → Sources → Enable JavaScript source maps ligado.
Ler um erro em trinta segundos
Um roteiro de leitura, na ordem:
- Que família é?
SyntaxErrormanda você para a sintaxe, e nada rodou. Qualquer outra família rodou até ali. - A mensagem cita um nome?
x is not defined,reading 'cep',x is not a function— esse nome é a pista. Procure onde ele deveria ter sido definido. - Qual é o primeiro
atde arquivo seu? É onde quebrou. O segundo diz quem chamou; costuma ser onde a causa mora. - O valor era o esperado? Se a resposta é “não sei”, pare de adivinhar: coloque um breakpoint e inspecione o escopo no momento da falha.
Erro conhecido é erro barato. A trilha de JavaScript segue daqui para o depurador, onde essas mesmas stacks viram um lugar em que você pode parar o programa e olhar em volta. E se preferir revisar como capturar e relançar antes disso, volte em try catch em JavaScript — ou consulte o guia completo de JavaScript para ver onde cada assunto entra.
Perguntas frequentes
Qual a diferença entre ReferenceError e TypeError?
Por que o console.log antes do erro não apareceu?
A stack trace se lê de cima para baixo ou de baixo para cima?
Meu erro aponta para bundle.js linha 1, e agora?
Dúvidas e comentários
Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.
Entrar para perguntarÉ o mesmo login gratuito dos cursos.
Nenhuma dúvida por aqui ainda — a primeira pode ser a sua.
Todo o código deste artigo foi executado em Node 24.16.0, e as saídas exibidas são as reais — como produzimos este conteúdo.
Fontes consultadas
- MDN — Error — developer.mozilla.org
- MDN — Referência de erros do JavaScript — developer.mozilla.org
- Chrome DevTools — Map preprocessed code to source code — developer.chrome.com


