Como Lidar com Uncaught (in promise) TypeError
Você está depurando sua aplicação frontend quando o console exibe: Uncaught (in promise) TypeError: Cannot read property 'type' of undefined. Esta mensagem de erro contém dois problemas distintos que desenvolvedores frequentemente confundem. Compreender ambos é essencial para o tratamento adequado de erros de Promise em JavaScript.
Este artigo explica o que esse erro realmente significa, por que ele aparece e como lidar corretamente com rejeições de Promise não tratadas em ambientes de navegador.
Pontos-Chave
- A mensagem “Uncaught (in promise) TypeError” sinaliza dois problemas separados: um TypeError em tempo de execução e um manipulador de rejeição de Promise ausente.
- Causas comuns incluem Promises flutuantes (falta de
await), manipuladores.catch()esquecidos e acesso a propriedades emundefinedounull. - Envolva expressões
awaitemtry/catchou anexe.catch()no final de cada cadeia de Promise para prevenir rejeições não tratadas. - Use encadeamento opcional (
?.) e coalescência nula (??) para se proteger contra TypeErrors de propriedades indefinidas. - Reserve o evento
unhandledrejectionpara monitoramento e telemetria, não como substituto para tratamento local de erros.
O Que ‘Uncaught (in promise) TypeError’ Realmente Significa
Esta mensagem de erro comunica dois problemas separados:
- TypeError: Ocorreu um erro em tempo de execução—tipicamente ao acessar uma propriedade em
undefinedounull. - Uncaught (in promise): A Promise que produziu este erro não tinha nenhum manipulador de rejeição anexado.
O navegador distingue esses casos porque rejeições de Promise se comportam de forma diferente de erros síncronos. Quando um TypeError síncrono ocorre, a execução para imediatamente. Quando o mesmo erro ocorre dentro de uma Promise, a rejeição se propaga através da cadeia de Promise. Se nenhum .catch() ou try/catch o tratar, o navegador o registra como uma rejeição de Promise não tratada.
Para uma referência mais aprofundada sobre o comportamento de Promises e propagação de erros, consulte a documentação MDN sobre Promises.
Causas Raiz Comuns em Código Frontend
Erros Lançados Dentro de Funções Async
Qualquer exceção dentro de uma função async automaticamente rejeita a Promise retornada:
async function fetchUserData(userId) {
const response = await fetch(`/api/users/${userId}`)
const data = await response.json()
return data.profile.name // TypeError se profile for undefined
}
fetchUserData(123) // Promise flutuante—nenhum manipulador anexado
Palavras-chave Await Ausentes
Esquecer await cria uma Promise flutuante que executa independentemente:
async function processData() {
fetchUserData(123) // Falta await—rejeição não é tratada
console.log('Done')
}
Manipuladores .catch() Esquecidos
Cadeias de Promise sem um bloco .catch() terminal deixam rejeições não tratadas:
fetch('/api/data')
.then(res => res.json())
.then(data => data.items[0].name) // Sem .catch()—TypeError se propaga
Anexação Tardia de Manipulador e Temporização de Microtask
Os navegadores determinam se uma rejeição foi tratada após o ponto de verificação de microtask atual. Se uma rejeição não tiver um manipulador até esse ponto, o navegador pode emitir um evento unhandledrejection e registrar um aviso no console. Anexar um manipulador logo depois ainda pode disparar o aviso em builds de desenvolvimento:
const promise = Promise.reject(new Error('Failed'))
promise.catch(err => console.log('Handled'))
Essa nuance de temporização explica por que algumas rejeições adequadamente tratadas ainda podem aparecer como não tratadas durante o desenvolvimento.
Discover how at OpenReplay.com.
Padrões Adequados de Tratamento de Erros com Async/Await
try/catch Local em Torno de Await
O padrão mais confiável envolve expressões await em try/catch:
async function fetchPokemon(id) {
try {
const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${id}`)
const data = await response.json()
return {
name: data.name,
type: data.types[0]?.type.name,
type2: data.types[1]?.type.name ?? null
}
} catch (error) {
console.error('Fetch failed:', error.message)
return null
}
}
Retornando Promises com Manipuladores Anexados
Ao chamar funções async, sempre trate a Promise retornada:
// Opção 1: await com try/catch
await fetchPokemon(25)
// Opção 2: .catch() na chamada
fetchPokemon(25).catch(handleError)
Encadeando .catch() Apropriadamente
Coloque .catch() no final das cadeias de Promise para capturar qualquer rejeição na cadeia:
Promise.all(urls.map(url => fetch(url).then(r => r.json())))
.then(results => processResults(results))
.catch(error => showErrorUI(error))
Usando o Evento unhandledrejection para Monitoramento
Os navegadores fornecem o evento unhandledrejection para monitoramento global de erros—não como mecanismo primário de tratamento de erros:
window.addEventListener('unhandledrejection', event => {
// Registrar no serviço de monitoramento de erros
errorTracker.capture(event.reason)
// Opcionalmente prevenir o erro padrão do console
event.preventDefault()
})
O evento complementar rejectionhandled dispara quando uma rejeição anteriormente não tratada posteriormente recebe um manipulador. Esses eventos são úteis para telemetria e para capturar erros que escapam do seu tratamento local, mas não devem substituir padrões adequados de try/catch e .catch().
Conclusão
A mensagem “Uncaught (in promise) TypeError” sinaliza tanto um erro em tempo de execução quanto tratamento de erro ausente. Aborde ambos os lados do problema: use encadeamento opcional (?.) e coalescência nula (??) para prevenir TypeErrors de propriedades indefinidas, e envolva operações assíncronas em try/catch ou anexe manipuladores .catch() a cada cadeia de Promise. Reserve o evento unhandledrejection para monitoramento, não para fluxo de controle. Esses padrões manterão seu código frontend resiliente e seu console limpo.
Perguntas Frequentes
Um Uncaught TypeError é um erro síncrono que interrompe a execução imediatamente. Um Uncaught (in promise) TypeError é o mesmo tipo de erro em tempo de execução, mas ocorreu dentro de uma Promise que não tinha manipulador de rejeição. O navegador adiciona o rótulo 'in promise' para indicar que a rejeição não foi tratada na cadeia assíncrona de Promise.
Sim. Um único .catch() no final de uma cadeia de Promise captura qualquer rejeição que ocorra em qualquer callback .then() precedente. A rejeição se propaga pela cadeia até encontrar um manipulador .catch(). Se nenhum existir, o navegador a reporta como uma rejeição de Promise não tratada.
Um bloco try/catch dentro de um callback .then() pode capturar erros síncronos lançados dentro daquele callback. No entanto, ele não pode capturar rejeições de Promise a menos que essas Promises sejam aguardadas (await) dentro de uma função async. Para tratar rejeições em uma cadeia .then(), anexe um .catch() no final da cadeia. Reserve try/catch principalmente para padrões async/await.
Não. O evento unhandledrejection é uma rede de segurança para capturar rejeições de Promise que escapam do seu tratamento local de erros. É mais adequado para logging e monitoramento. Sempre trate erros localmente com try/catch ou .catch() primeiro, e trate o listener de evento global como um fallback para diagnósticos.
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Check our GitHub repo and join the thousands of developers in our community.