Manipuladores Globais de Erro
ErrorUtils.setGlobalHandler e rejeições de promessa não tratadas.
Busque em todas as páginas da documentação
ErrorUtils.setGlobalHandler e rejeições de promessa não tratadas.
Os error boundaries do React cobrem apenas a árvore de renderização. ErrorUtils.setGlobalHandler é o hook do React Native para erros de JavaScript não capturados - incluindo muitas falhas que nunca tocam um boundary. Combine-o com tratamento de erro async/await disciplinado para que as rejeições de promessa não sejam silenciosas em produção.
Cartão de receita de referência rápida - pronto para copiar e colar.
// src/bootstrap/installGlobalErrorHandlers.ts
// Importe isso uma vez a partir do seu ponto de entrada do aplicativo (index.js / _layout.tsx) antes de outro código do aplicativo.
type GlobalHandler = (error: Error, isFatal?: boolean) => void;
declare const ErrorUtils: {
getGlobalHandler(): GlobalHandler;
setGlobalHandler(handler: GlobalHandler): void;
};
export function installGlobalErrorHandlers(report: (error: Error, meta: { isFatal: boolean }) => void) {
const previous = ErrorUtils.getGlobalHandler();
ErrorUtils.setGlobalHandler((error, isFatal = false) => {
report(error, { isFatal });
previous(error, isFatal);
});
}// app/_layout.tsx (root do Expo Router) - chame antes de renderizar provedores
import { installGlobalErrorHandlers } from "@/bootstrap/installGlobalErrorHandlers";
import { Stack } from "expo-router";
installGlobalErrorHandlers((error, { isFatal }) => {
console.error("[global]", isFatal ? "FATAL" : "non-fatal", error);
// crashReporter.captureException(error, { extra: { isFatal } });
});
export default function RootLayout() {
return <Stack />;
}Quando usar isso:
isFatal, canal de build, rota) em cada relatório de falha.// installGlobalErrorHandlers.ts - módulo de bootstrap completo
type GlobalHandler = (error: Error, isFatal?: boolean) => void;
declare const ErrorUtils: {
getGlobalHandler(): GlobalHandler;
setGlobalHandler(handler: GlobalHandler): void;
};
export type ErrorReport = {
message: string;
stack?: string;
isFatal: boolean;
kind: "global" | "unhandled-rejection";
};
const reports: ErrorReport[] = [];
export function getCapturedReports() {
return [...reports];
}
function normalizeError(reason: unknown): Error {
if (reason instanceof Error) return reason;
return new Error(typeof reason === "string" ? reason : JSON.stringify(reason));
}
function record(error: Error, meta: { isFatal: boolean; kind: ErrorReport["kind"] }) {
reports.push({
message: error.message,
stack: error.stack,
isFatal: meta.isFatal,
kind: meta.kind,
});
console.error(`[${meta.kind}]`, meta.isFatal ? "FATAL" : "non-fatal", error.message);
}
export function installGlobalErrorHandlers() {
const previous = ErrorUtils.getGlobalHandler();
ErrorUtils.setGlobalHandler((error, isFatal = false) => {
record(error, { isFatal, kind: "global" });
previous(error, isFatal);
});
// Cinto e suspensórios: registro explícito de rejeição não tratada (Hermes / ferramentas de desenvolvimento RN também podem rotear isso)
const g = globalThis as typeof globalThis & {
onunhandledrejection?: (event: { reason?: unknown }) => void;
};
g.onunhandledrejection = (event) => {
const error = normalizeError(event.reason);
record(error, { isFatal: false, kind: "unhandled-rejection" });
};
}
// --- Telas de demonstração ---
import { useEffect, useState } from "react";
import { Pressable, ScrollView, StyleSheet, Text, View } from "react-native";
installGlobalErrorHandlers();
function causeUnhandledRejection() {
void Promise.reject(new Error("falha na sincronização de faturamento"));
}
function causeThrowInTimer() {
setTimeout(() => {
throw new Error("lançamento no timer fora do React");
}, 0);
}
export default function App() {
const [tick, setTick] = useState(0);
useEffect(() => {
const id = setInterval(() => setTick((t) => t + 1), 1000);
return () => clearInterval(id);
}, []);
const latest = getCapturedReports().slice(-3);
return (
<ScrollView contentContainerStyle={styles.container}>
<Text style={styles.title}>Manipuladores Globais de Erro</Text>
<Text style={styles.sub}>Relógio: {tick}s (aplicativo ainda em execução)</Text>
<Pressable style={styles.btn} onPress={causeUnhandledRejection}>
<Text style={styles.btnLabel}>Disparar rejeição não tratada</Text>
</Pressable>
<Pressable style={styles.btn} onPress={causeThrowInTimer}>
<Text style={styles.btnLabel}>Disparar lançamento no timer</Text>
</Pressable>
<Text style={styles.section}>Últimos relatórios capturados</Text>
{latest.length === 0 && <Text style={styles.meta}>Ainda não há nada - toque em um botão acima.</Text>}
{latest.map((r, i) => (
<View key={`${r.message}-${i}`} style={styles.card}>
<Text style={styles.cardTitle}>
[{r.kind}] {r.isFatal ? "FATAL" : "non-fatal"}
</Text>
<Text style={styles.cardBody}>{r.message}</Text>
</View>
))}
</ScrollView>
);
}
const styles = StyleSheet.create({
container: { padding: 20, gap: 12 },
title: { fontSize: 24, fontWeight: "800" },
sub: { color: "#64748b" },
section: { fontSize: 16, fontWeight: "700", marginTop: 8 },
meta: { color: "#94a3b8" },
btn: { backgroundColor: "#2563eb", padding: 14, borderRadius: 8 },
btnLabel: { color: "#fff", fontWeight: "600", textAlign: "center" },
card: { backgroundColor: "#f1f5f9", padding: 12, borderRadius: 8 },
cardTitle: { fontWeight: "700", marginBottom: 4 },
cardBody: { color: "#334155" },
});O que isso demonstra:
ErrorUtils.setGlobalHandler instalado uma vez no carregamento do módulo antes da renderização da UI.isFatal é registrado - o triagem de produção distingue paradas críticas de erros suaves.onunhandledrejection captura falhas de promessa flutuantes que nunca atingem um boundary.ErrorUtils.setGlobalHandler(fn) substitui esse manipulador. Sua função é executada primeiro; você normalmente registra, enriquece e, em seguida, chama o manipulador anterior.isFatal indica se o runtime trata o erro como terminal. Erros fatais podem encerrar a execução saudável do bundle JS; sempre relate-os imediatamente..catch. Em desenvolvimento, o LogBox as exibe; em produção, o comportamento depende da versão do Hermes/RN - nunca confie na sorte._layout.tsx raiz) antes que roteadores, análises e código de recursos sejam carregados.| Método | Propósito |
|---|---|
getGlobalHandler() | Retorna o manipulador atualmente instalado (encadeie este) |
setGlobalHandler(fn) | Instala seu manipulador para erros de JS não capturados |
| Parâmetro | Tipo | Descrição |
|---|---|---|
error | Error | O erro de JS lançado ou normalizado |
isFatal | boolean (opcional) | Quando true, o runtime considera o erro terminal - priorize o relatório de falhas |
setGlobalHandler e getGlobalHandler retornam void / uma função manipuladora, respectivamente. Não há retorno de promessa - o manipulador é executado de forma síncrona no caminho de falha.
// app/_layout.tsx - topo do arquivo, antes dos componentes
import { installGlobalErrorHandlers } from "@/bootstrap/installGlobalErrorHandlers";
import * as Sentry from "@sentry/react-native";
Sentry.init({ dsn: process.env.EXPO_PUBLIC_SENTRY_DSN });
installGlobalErrorHandlers((error, { isFatal }) => {
Sentry.captureException(error, { extra: { isFatal } });
});
export default function RootLayout() {
return <RootProviders />;
}installGlobalErrorHandlers| Abordagem | Papel |
|---|---|
.catch / try/catch em cada API async | Primária - evita que rejeições se tornem globais |
onunhandledrejection em globalThis | Repórter secundário no código do aplicativo |
Manipulador global ErrorUtils | Captura muitos lançamentos não capturados; algumas rejeições são roteadas aqui em produção |
| SDK de repórter de falhas | Frequentemente instrumenta ambos automaticamente |
// Fronteira da API - prefira corrigir na origem
export async function fetchBalance(): Promise<number> {
try {
const res = await fetch("/api/balance");
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = (await res.json()) as { balance: number };
return json.balance;
} catch (error) {
// Converta para o tipo Result ou relance para um estado de erro controlado na tela
throw error instanceof Error ? error : new Error("falha ao buscar saldo");
}
}
// Tarefas "fire-and-forget" ainda devem lidar com falhas
void syncAnalytics().catch((error) => {
console.warn("falha na sincronização de análises", error);
});| Camada | Captura | Experiência do usuário |
|---|---|---|
| try/catch | Chamadas async/nativas conhecidas | Erro inline, toast, mensagem de formulário |
| Error boundary | Lançamentos de renderização/ciclo de vida | Fallback de tela com Retentar |
| Manipulador global ErrorUtils | Erros de JS não capturados fora dos boundaries | Relata/registra; UI fatal padrão do RN em desenvolvimento |
| SDK de falha nativa | Falhas nativas + JS | Painel de falhas, replay de sessão |
Não renderize UI do React dentro de setGlobalHandler - a árvore pode estar instável. Adie a UX do produto para boundaries e Texto de Erro Voltado para o Usuário.
type ReportFn = (error: Error, meta: { isFatal: boolean }) => void;
declare const ErrorUtils: {
getGlobalHandler(): (error: Error, isFatal?: boolean) => void;
setGlobalHandler(handler: (error: Error, isFatal?: boolean) => void): void;
};
export function installGlobalErrorHandlers(report: ReportFn): void {
const previous = ErrorUtils.getGlobalHandler();
ErrorUtils.setGlobalHandler((error, isFatal = false) => {
report(error, { isFatal: !!isFatal });
previous(error, isFatal);
});
}
function normalizeReason(reason: unknown): Error {
if (reason instanceof Error) return reason;
return new Error(String(reason));
}ErrorUtils é um global do React Native - ele não é importado de react-native em todos os templates; declare-o uma vez em um globals.d.ts se necessário.Error antes de registrar para que os repórteres sempre recebam uma forma Error.Substituir o manipulador global sem encadear - O redbox de desenvolvimento e o encanamento de relatórios de falhas nativas param de funcionar. Correção: Sempre chame const prev = ErrorUtils.getGlobalHandler() e invoque prev(error, isFatal) após relatar.
Registrar o manipulador várias vezes - Cada recarga a quente ou remontagem de layout envolve outra camada; os relatórios se duplicam. Correção: Proteja com uma flag let installed = false no nível do módulo.
Esperar que o manipulador global mostre UI de tela amigável - O React pode estar no meio da renderização ou corrompido. Correção: Relate no manipulador; mostre a UI de recuperação através de error boundaries.
Chamadas void someAsync() não tratadas - Promessas flutuantes ignoram try/catch e boundaries. Correção: void someAsync().catch(handle) ou aguarde dentro de um manipulador de eventos com try/catch.
Engolir erros fatais - Retornar cedo sem chamar o manipulador anterior oculta erros catastróficos em desenvolvimento. Correção: Relate, e então sempre encadeie, a menos que você controle totalmente o comportamento de falha em um cliente de desenvolvimento personalizado.
Instalar manipuladores após importações preguiçosas - Erros durante a avaliação antecipada do módulo perdem seu manipulador. Correção: Importe o bootstrap primeiro em index.js ou no topo de app/_layout.tsx.
Registro duplo com Sentry - O Sentry também aplica patches em manipuladores; a ordem importa. Correção: Sentry.init() primeiro, depois enriquecimento personalizado que encadeia, ou use os hooks do Sentry exclusivamente.
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
ErrorUtils.setGlobalHandler | Endurecimento de produção RN de linha de base | Você só precisa de contenção em tempo de renderização (use boundaries) |
| SDK de repórter de falhas sozinho (Sentry) | Instrumentação gerenciada, simbolização | Você precisa de registro local personalizado antes da inicialização de terceiros |
| try/catch em todos os lugares | Fluxos async previsíveis | Lançamentos de renderização de componentes de terceiros |
| Error boundaries do React | UX de fallback em nível de tela | Erros de timer/nativos fora do React |
| LogBox (apenas desenvolvimento) | Depuração local | Captura de falhas de produção |
ErrorUtils é um objeto global fornecido pelo runtime do React Native com getGlobalHandler e setGlobalHandler. É o hook de último recurso para erros de JavaScript não capturados no bundle JS.
No topo de app/_layout.tsx (importação de efeito colateral) ou em index.js antes de registerRootComponent. Deve ser executado uma vez, o mais cedo possível - antes que a navegação e os módulos de recursos sejam carregados.
Quando true, o runtime trata o erro como terminal - o processo ou contexto JS pode não continuar de forma confiável. Relate imediatamente e evite tentar UI de recuperação complexa a partir do manipulador global.
Não - eles resolvem problemas diferentes. Boundaries contêm erros de renderização por tela. O manipulador global captura erros não capturados fora do caminho de renderização do React (timers, alguns callbacks nativos, lançamentos não tratados).
Em desenvolvimento, o LogBox avisa. Em produção, o comportamento varia - algumas rejeições são roteadas para o manipulador global, muitas não são. Trate .catch explícito nas fronteiras da API como obrigatório; use onunhandledrejection como uma rede de segurança secundária.
Geralmente não - a árvore pode estar instável e os alertas se empilham de forma irritante. Relate o erro e deixe os error boundaries ou a próxima inicialização do aplicativo apresentarem a UX. Falhas nativas podem encerrar a sessão de qualquer maneira.
let installed = false;
export function installGlobalErrorHandlers() {
if (installed) return;
installed = true;
// setGlobalHandler...
}Proteja a instalação no escopo do módulo em desenvolvimento.
Prefira o ErrorUtils global com uma declaração ambiente TypeScript. Os templates variam; o runtime sempre expõe o global no thread JS.
Chame Sentry.init() primeiro, e então confie no patching automático de manipuladores do Sentry ou encadeie seu enriquecimento após getGlobalHandler(). Veja sentry-expo / @sentry/react-native.
Erros capturados por try/catch, rejeições de promessa tratadas e erros contidos por error boundaries do React (a menos que sejam relançados). Falhas apenas nativas podem ignorar completamente os manipuladores JS - precisam de SDKs nativos.
Raramente. Prefira deixar o usuário relançar ou navegar para a página inicial a partir de um fallback de boundary. reloadAsync() do expo-updates é um martelo pesado - reserve para fluxos de recuperação OTA, não para todos os erros de JS.
Dispare um lançamento de timer ou Promise.reject sem .catch, como no exemplo de trabalho. Confirme se seus logs de repórter são disparados e, em seguida, verifique se o redbox de desenvolvimento ainda aparece porque você encadeou o manipulador anterior.
Hermes é o motor JS padrão no React Native 0.86 / Expo SDK 57. Rastros de pilha e roteamento de rejeição de promessa diferem ligeiramente do JSC, mas ErrorUtils permanece o ponto de integração estável.
error.message e stackisFatalEvite PII nos metadados de falha global.
Fundamentos cobre camadas de try/catch, boundaries e globais. Esta página implementa a camada global - veja Fundamentos de Tratamento de Erros para o quadro completo.
Versões da Stack: Esta página foi escrita para React 19.2.3, React Native 0.86.0 e Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026