Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

Unhandled Rejections no Node.js

Atualizado em: 4 de outubro de 2026

Rack de servidores processando fluxos de dados no Node.js

Uma unhandled rejection acontece quando uma Promise é rejeitada e nenhum handler de erro é associado a tempo. Em Node.js, isso indica que uma operação assíncrona falhou fora do fluxo de tratamento esperado. O resultado pode ser encerramento do processo, aviso, estado inconsistente ou perda de contexto, conforme a versão e a configuração.

A solução não é adicionar um listener global e continuar normalmente. O objetivo deve ser encontrar a Promise sem tratamento, preservar diagnóstico e encerrar de forma segura quando a política considerar a falha fatal.

Exemplo simples

async function loadConfiguration() {
  throw new Error('Configuração inválida');
}

loadConfiguration();

A Promise retornada não foi aguardada nem recebeu catch.

Tratamento correto

try {
  await loadConfiguration();
} catch (error) {
  logger.fatal({ err: error }, 'Falha ao carregar configuração');
  throw error;
}

No bootstrap, a falha normalmente deve impedir o servidor de iniciar.

Fire-and-forget

Este padrão é perigoso:

sendAnalytics(event);

Mesmo quando o resultado não é necessário, a rejeição precisa ser observada:

void sendAnalytics(event).catch((error) => {
  logger.warn({ err: error }, 'Falha ao enviar analytics');
});

Use fire-and-forget somente para tarefa realmente opcional. Para trabalho importante, use fila durável.

Await esquecido

async function controller(req, res) {
  service.create(req.body);
  res.status(202).end();
}

Se service.create falha, a resposta já foi enviada. Use await ou enfileire explicitamente.

Array.forEach assíncrono

items.forEach(async (item) => {
  await processItem(item);
});

forEach ignora Promises. Alternativas:

for (const item of items) {
  await processItem(item);
}

await Promise.all(items.map(processItem));

Promise.all inicia tudo ao mesmo tempo. Para listas grandes, limite concorrência.

map sem Promise.all

const tasks = items.map(async (item) => processItem(item));

Se tasks nunca é aguardado, rejeições podem ficar sem tratamento.

setTimeout assíncrono

setTimeout(async () => {
  await operation();
}, 1000);

O timer não observa a Promise. Trate dentro:

setTimeout(() => {
  void operation().catch((error) => {
    logger.error({ err: error }, 'Tarefa agendada falhou');
  });
}, 1000);

EventEmitter

Callbacks assíncronos em eventos também precisam de catch:

emitter.on('message', (message) => {
  void processMessage(message).catch(handleMessageError);
});

Uma fila real deve controlar ack, retry e dead letter.

Express

Em frameworks, garanta que rejeições de handlers cheguem ao middleware de erro. Dependendo da versão, use wrapper:

const asyncHandler = (handler) => (req, res, next) => {
  Promise.resolve(handler(req, res, next)).catch(next);
};

Listener global

process.on('unhandledRejection', (reason, promise) => {
  logger.fatal({
    err: reason,
  }, 'Promise rejeitada sem tratamento');

  beginFatalShutdown('unhandledRejection');
});

O listener serve para diagnóstico e shutdown. Não use para “resolver” a Promise ou continuar atendendo.

Por que não continuar

A rejeição pode ter ocorrido durante atualização parcial, inicialização, transação, lock ou processamento de mensagem. O código que deveria compensar não foi executado. O estado do processo pode ser desconhecido.

Política de processo

Defina uma política explícita:

  • registrar como fatal;
  • marcar readiness como false;
  • parar de aceitar trabalho;
  • drenar dentro de prazo curto;
  • fechar recursos;
  • encerrar com código não zero;
  • permitir reinício pelo supervisor.

uncaughtException

Unhandled rejection e uncaught exception são sinais diferentes, mas ambos indicam falha fora do tratamento normal. Centralize o shutdown fatal sem registrar duas vezes.

process.on('uncaughtException', (error, origin) => {
  logger.fatal({ err: error, origin }, 'Exceção não capturada');
  beginFatalShutdown(origin);
});

Idempotência do shutdown

let fatalShutdownPromise;

function beginFatalShutdown(reason) {
  if (!fatalShutdownPromise) {
    fatalShutdownPromise = shutdown({ reason, exitCode: 1 });
  }
  return fatalShutdownPromise;
}

Vários eventos podem ocorrer durante a falha. Execute o fluxo uma vez.

Não faça trabalho complexo no handler

O processo está em situação anormal. Evite chamadas externas longas, uploads grandes e lógica de negócio. Faça logging mínimo e limpeza limitada.

Monitor externo

Use systemd, Kubernetes, PM2 ou outro supervisor para reiniciar. O próprio processo não deve tentar reiniciar-se.

Crash loop

Se o bug ocorre no startup, o supervisor pode reiniciar continuamente. Use backoff, limite de reinícios, alertas e rollback.

Ambiente de teste

Configure testes para falhar quando existe rejeição não tratada. Runners modernos normalmente fazem isso, mas confirme a política.

Helper para Promises ignoradas

function runDetached(promise, context) {
  void promise.catch((error) => {
    logger.error({ err: error, ...context }, 'Tarefa destacada falhou');
  });
}

Nomear a intenção deixa claro que a tarefa é destacada. Ainda assim, não use para trabalho crítico.

eslint

Regras de TypeScript ESLint podem detectar Promises flutuantes e awaits incorretos. Exemplos de categorias úteis:

  • no-floating-promises;
  • no-misused-promises;
  • require-await;
  • return-await conforme política.

Adote gradualmente e corrija exceções conscientemente.

TypeScript

Tipar retornos como Promise ajuda, mas TypeScript não obriga await. Linters complementam o compilador.

void explícito

void optionalTask().catch(handleOptionalError);

O operador void sinaliza que o resultado é ignorado intencionalmente, sem dispensar o catch.

Promise constructor

Evite criar Promise desnecessariamente ao envolver função async. Erros dentro de callbacks precisam chamar reject.

return new Promise((resolve, reject) => {
  legacyApi((error, result) => {
    if (error) {
      reject(error);
      return;
    }
    resolve(result);
  });
});

Callbacks que lançam

Um throw dentro de callback assíncrono não é capturado por try/catch externo:

try {
  setTimeout(() => {
    throw new Error('Falha');
  }, 0);
} catch {
  // não captura
}

Trate dentro do callback ou converta para Promise observada.

Promise.race

Uma Promise que perde a corrida continua executando. Se ela falhar, a Promise original já possui handlers internos de race, mas o recurso continua. Use AbortController para cancelar o perdedor.

Timeout ingênuo

await Promise.race([
  operation(),
  timeoutPromise(5000),
]);

Isso não cancela operation. Passe signal.

Streams

Pipeline baseado em Promise precisa ser aguardado:

await pipeline(source, transform, destination);

Iniciar sem await pode gerar rejeição após a função retornar.

Worker Threads

Erros e exits de workers precisam ser observados. Uma Promise que representa a tarefa deve rejeitar e ser aguardada.

Processos filhos

Trate error, close e exit code. Não presuma que iniciar o processo significa sucesso.

Mensageria

Um handler que retorna Promise deve ser aguardado pela biblioteca. Confirme o contrato. Ack antes da conclusão perde mensagens em falha.

Logs

Inclua stack, cause, origin, versão e request/trace ID quando disponíveis. Não registre a Promise inteira, que raramente ajuda e pode conter referências.

Process Reports

Em falhas fatais, um Process Report pode capturar contexto. Gere com cuidado e limite para evitar disco cheio em crash loop.

Métricas

Unhandled rejection deve ser rara. Conte eventos e alerte imediatamente. Também acompanhe reinícios e crash loops.

Testes de integração

Crie um processo filho que dispara a falha e confirme exit code, log e shutdown. Não derrube o runner principal.

Erros comuns

  • adicionar listener e continuar;
  • ignorar Promise;
  • usar forEach async;
  • não tratar timer async;
  • responder antes de await;
  • fazer trabalho complexo no handler;
  • reiniciar dentro do processo;
  • não limitar crash loop;
  • não usar linter;
  • confundir timeout com cancelamento.

Fluxo recomendado

Aguarde Promises, trate tarefas destacadas explicitamente, habilite lint e considere rejeição não tratada uma falha fatal. Combine com Tratamento de Erros, Pino, Graceful Shutdown e Process Reports.

Consulte a documentação oficial de unhandledRejection e a referência de uncaughtException.

10 melhores cursos de programação em 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita