Cannot read properties of undefined: como resolver
As quatro causas reais desse erro, cada uma reproduzida no Node com stack trace e a correção ao lado — array vazio, API, ordem assíncrona e typo.
A mensagem completa é assim:
Ela quer dizer uma coisa só: você usou ponto (ou colchete) em cima de um valor
que é undefined. O JavaScript não tem o que buscar dentro do nada, então
interrompe ali.
O que a mensagem já entrega, e quase ninguém aproveita: o nome entre
parênteses é a propriedade que você tentou ler. Ou seja, o undefined é
exatamente o que está imediatamente antes do ponto. Em
pedido.cliente.endereco.cidade, um erro (reading 'cidade') significa que
endereco é undefined — pedido e cliente estão vivos.
Todo o código abaixo foi executado no Node 24.16.0 e as saídas são reais.
Leia a expressão como um endereço completo
Pense em pedido.cliente.endereco.cidade como um endereço escrito em etapas:
prédio, andar, apartamento, cômodo. Para chegar à cidade, o JavaScript precisa
encontrar cada parte anterior. Se endereco não existe, não há como abrir a
porta seguinte chamada cidade.
O termo técnico é acesso a propriedade. O erro não afirma que a propriedade
final está vazia; afirma que o valor antes dela é undefined ou null e,
por isso, não pode ser consultado. Faça o diagnóstico sem adivinhar: copie a
expressão que falhou, remova a última propriedade e imprima o resultado. Repita
até encontrar o primeiro trecho ausente. Esse movimento de voltar uma porta é
mais confiável que espalhar ?. pelo caminho, porque mostra quem deveria ter
construído o dado.
O código mínimo que reproduz
const pedidos = [];
const ultimo = pedidos[0];
console.log('total do último pedido:', ultimo.total);Duas linhas úteis nessa saída: o arquivo com linha e coluna (relatorio.mjs:4:47)
e o cursor ^ apontando o ponto exato. Comece por ali, sempre.
Causa 1 — o array está vazio
É a causa mais comum e a mais silenciosa: em desenvolvimento a lista tem itens, em produção ela chega vazia num dia atípico.
Quebrado:
const pedidos = [];
const ultimo = pedidos[0];
console.log('total do último pedido:', ultimo.total);pedidos[0] num array vazio não lança erro — devolve undefined. O erro só
estoura na linha seguinte, uma linha depois da causa.
Corrigido:
const pedidos = [];
const ultimo = pedidos[0];
console.log('total do último pedido:', ultimo?.total ?? 0);
if (pedidos.length === 0) {
console.log('nenhum pedido para exibir');
}Note que a correção tem duas partes. ?. impede a exceção; o if é o que
efetivamente resolve o problema de produto — mostrar um estado vazio de verdade
em vez de um zero mentiroso.
Causa 2 — a API respondeu, mas sem o campo
O fetch não lança erro quando a resposta é 404 ou 500. Ele resolve
normalmente, e você segue lendo um corpo que não tem a forma esperada.
Os dois trechos abaixo rodaram contra o mesmo servidor de mentira, subido no topo do arquivo — é ele que responde 404 na porta 4310, e é por isso que o stack trace aponta uma linha mais adiante do que o trecho mostrado:
import { createServer } from 'node:http';
const servidor = createServer((req, res) => {
res.writeHead(404, { 'content-type': 'application/json' });
res.end(JSON.stringify({ erro: 'cliente não encontrado' }));
});
await new Promise((pronto) => servidor.listen(4310, pronto));Quebrado:
const resposta = await fetch('http://localhost:4310/clientes/99');
const cliente = await resposta.json();
console.log('status:', resposta.status);
console.log('corpo:', cliente);
console.log('cidade:', cliente.endereco.cidade);O log do corpo já denuncia tudo: veio { erro: ... }, e nesse objeto não existe
endereco.
Corrigido:
const resposta = await fetch('http://localhost:4310/clientes/99');
if (!resposta.ok) {
console.log(`API respondeu ${resposta.status} — nada a renderizar`);
} else {
const cliente = await resposta.json();
console.log('cidade:', cliente.endereco?.cidade ?? 'não informada');
}Causa 3 — a ordem de execução assíncrona
O valor vai existir. Só que ainda não existia quando você o leu. Esta é a causa
que mais confunde, porque o código parece estar na ordem certa de cima para
baixo — e está. O que não é sequencial é o momento em que o dado chega. Se
await, callback e Promise ainda são território nebuloso, vale ler a
lição sobre funções antes de seguir: aqui o
problema é quando a função roda, não o que ela faz.
Quebrado:
let cliente;
function carregarCliente() {
setTimeout(() => {
cliente = { nome: 'Ana Souza', endereco: { cidade: 'Sorocaba' } };
}, 100);
}
carregarCliente();
console.log('cidade:', cliente.endereco.cidade);carregarCliente() retornou imediatamente; o setTimeout só roda depois que a
pilha esvazia. O console.log chegou antes.
Corrigido — a função devolve uma Promise, e quem chama espera:
function carregarCliente() {
return new Promise((resolve) => {
setTimeout(() => resolve({ nome: 'Ana Souza', endereco: { cidade: 'Sorocaba' } }), 100);
});
}
const cliente = await carregarCliente();
console.log('cidade:', cliente.endereco.cidade);O sinal desta causa é característico: o dado aparece na tela um instante depois,
ou aparece quando você adiciona um console.log antes (porque isso muda o
tempo). Se o bug some ao observá-lo, é aqui.
Causa 4 — typo em propriedade aninhada
A causa mais boba e a mais difícil de enxergar: o objeto está certo, o caminho
é que está errado por uma letra. Vale lembrar que
const não congela o conteúdo de um objeto — o
objeto pode ter sido alterado em outro ponto do código, e a propriedade que você
procura simplesmente não é mais a que você espera.
Quebrado:
const pedido = {
id: 1042,
cliente: {
nome: 'Ana Souza',
enderecoEntrega: { cidade: 'Sorocaba', uf: 'SP' },
},
};
console.log(pedido.cliente.endereco.cidade);O campo chama enderecoEntrega, não endereco. E note o cursor: ele aponta
cidade, o que confirma a regra do começo — o undefined é endereco.
Corrigido — e, antes da correção, o diagnóstico:
console.log(Object.keys(pedido.cliente));
console.log(pedido.cliente.enderecoEntrega.cidade);Object.keys no objeto anterior ao ponto que falhou é o atalho mais rápido
de depuração que existe para esta família de erro. Em dois segundos você vê o
nome verdadeiro do campo.
Como evitar
Optional chaining (?.)
Interrompe a expressão e devolve undefined em vez de lançar erro, se o valor
antes dele for null ou undefined.
const pedido = { id: 1042, cliente: { nome: 'Ana Souza' } };
console.log(pedido.cliente?.enderecoEntrega?.cidade);
console.log(pedido.cliente?.enderecoEntrega?.cidade ?? 'retirar na loja');
console.log(pedido.itens?.[0]?.nome ?? 'carrinho vazio');
console.log(pedido.calcularTotal?.() ?? 'sem cálculo disponível');Funciona em três formas: propriedade (a?.b), índice (a?.[0]) e chamada de
função (a?.()). Esta última é a saída limpa para o parente próximo deste erro,
o x is not a function.
O ?. precisa estar em cada elo
Colocar um só, no começo, não protege o resto da cadeia:
const pedido = { id: 1042, cliente: { nome: 'Ana Souza' } };
console.log(pedido.cliente?.enderecoEntrega.cidade);cliente existe, então a cadeia não curto-circuita; enderecoEntrega é
undefined e o .cidade seguinte quebra do mesmo jeito. O ?. protege apenas
o elo em que ele está escrito.
Nullish coalescing (??) e não ||
?? só entra em ação para null e undefined. || entra para qualquer valor
falso — e 0 e string vazia são valores legítimos:
const pedido = { desconto: 0, observacao: '' };
console.log(pedido.desconto || 'sem desconto');
console.log(pedido.desconto ?? 'sem desconto');
console.log(pedido.observacao || 'sem observação');
console.log(pedido.observacao ?? 'sem observação');A primeira linha é um bug clássico de e-commerce: desconto zero virou texto. Com
??, o zero sobrevive — e a quarta linha da saída está em branco de propósito,
porque a string vazia também sobreviveu.
Roteiro de diagnóstico em quatro passos
- Leia o nome entre parênteses. O
undefinedé o que está imediatamente antes dele na expressão. - Vá até o arquivo, linha e coluna do stack trace. O cursor
^marca a coluna. - Imprima o objeto anterior ao ponto que falhou, com
Object.keys(). - Pergunte quem produziu esse valor: array vazio, resposta de rede, ou código que ainda não terminou de rodar? A resposta decide a correção.
Se o valor for null em vez de undefined, a mensagem muda mas o roteiro é o
mesmo. E se o problema for o oposto — o objeto existe, mas o método não —
a explicação está em funções em JavaScript. Para
entender por que uma variável pode existir sem valor,
variáveis em JavaScript cobre a zona morta
temporal e o undefined do var.
Se esses dois assuntos ainda são novos, o guia de JavaScript mostra em que ordem estudar cada peça — este erro costuma aparecer justamente na fase em que se começa a consumir API e o dado deixa de ser escrito à mão. E se o trecho que quebrou veio de um assistente de IA, vale saber como um LLM produz código: ele escreve o caminho mais provável, não o caminho verificado — a suposição de que o campo sempre existe é exatamente o tipo de coisa que sai plausível e falsa.
Perguntas frequentes
Qual a diferença entre esse erro e o de null?
Optional chaining resolve todos os casos?
Por que o erro aponta uma linha que parece correta?
Como descobrir qual parte da expressão é undefined?
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 — TypeError: cannot read property of undefined — developer.mozilla.org
- MDN — Optional chaining (?.) — developer.mozilla.org


