← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

Unhandled Promise Rejection

JavaScript ES2015 Intermediate
debt(d7/e3/b5/t7)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). ESLint and TypeScript are listed in detection_hints.tools and can flag some patterns (missing await, missing .catch()), but fire-and-forget async calls in loops and Promise.all() misuse often slip past static analysis — the rejection itself may only surface at runtime under specific conditions, and global unhandledrejection handlers are needed to observe them in production.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix describes adding global handlers at entry points and wrapping calls with await/.catch() — a small, repeatable pattern that may touch multiple call sites but doesn't require cross-cutting architectural change. It's more than a single-line patch but well within one component or entry-point scope.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). The issue applies to both web and CLI contexts and recurs across any async code in the codebase. Developers must habitually audit every async call and Promise chain, and the absence of global handlers means monitoring is incomplete — this imposes an ongoing cost across many work streams without being fully architectural.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception field directly states the trap: developers assume a floating rejected Promise is harmless, but in Node.js 15+ it terminates the process and in browsers it silently fires an event that may go unmonitored. This contradicts the intuition that 'fire-and-forget' is safe, and contradicts how synchronous thrown errors are typically visible. The gap between expected (silent ignore) and actual (process crash or unmonitored event) is serious.

About DEBT scoring →

Also Known As

UnhandledPromiseRejection unhandledrejection event

TL;DR

An unhandled Promise rejection occurs when a rejected Promise has no .catch() or try/catch handler — Node.js 15+ terminates the process on unhandled rejection by default.

Explanation

When a Promise rejects and there is no rejection handler, the error is silently swallowed in older environments. Modern Node.js (15+) terminates the process on unhandled rejection. Browsers fire the window.unhandledrejection event. Common causes: async functions called without await, Promise.all() where one rejection goes unnoticed, and fire-and-forget patterns without .catch(). Fix: always await async calls in try/catch, add .catch() to floating Promises, or use Promise.allSettled() when partial failure is acceptable.

Common Misconception

A floating Promise that rejects won't affect the application — in Node.js 15+ it terminates the process; in browsers it fires unhandledrejection which monitoring should capture.

Why It Matters

Unhandled rejections are a top source of silent failures in Node.js — the operation fails, no error is logged, and the application continues in a corrupted state.

Common Mistakes

  • Not awaiting async function calls: doSomethingAsync() without await
  • Using Promise.all() when Promise.allSettled() would handle partial failure
  • Not adding a global unhandledrejection listener for monitoring

Code Examples

✗ Vulnerable
fetch('/api/data')
    .then(r => r.json())
    .then(data => processData(data));
// Rejection not handled — UnhandledPromiseRejection in Node 15+
✓ Fixed
fetch('/api/data')
    .then(r => r.json())
    .then(data => processData(data))
    .catch(err => console.error('Failed:', err));

// Or with async/await:
try {
    const data = await fetch('/api/data').then(r => r.json());
    processData(data);
} catch (err) {
    console.error('Failed:', err);
}

Added 22 Mar 2026
Edited 23 Mar 2026
Views 84
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings S 0 pings M 1 ping T 0 pings W 0 pings T 0 pings F 0 pings S 1 ping S 1 ping M 0 pings T 0 pings W 0 pings T 2 pings F 1 ping S 1 ping S 1 ping M 0 pings T 1 ping W 0 pings T 0 pings F 0 pings S 0 pings S 2 pings M 0 pings T 0 pings W 0 pings T 1 ping F 2 pings S 0 pings S 2 pings M
SEMrush 2
No pings yesterday
Scrapy 11 Amazonbot 10 Google 7 Ahrefs 5 PetalBot 5 SEMrush 4 Perplexity 3 Unknown AI 3 Majestic 2 Brave Search 2 Applebot 2 Meta AI 1 Twitter/X 1 Bing 1
crawler 54 crawler_json 2 pre-tracking 1
🧱 FUNDAMENTALS — new to this? Start with the ground floor.
JavaScript javascript The programming language of the browser — it reads and modifies the page (the DOM), reacts to user events, and fetches data without reloading.

JavaScript is the only language browsers execute, so every interactive behaviour on the web goes through it. Its two defining traits — single-threaded event loop and loose typing (== coercion) — explain the majority of both its bugs and its design patterns.

💡 Default to const, use === always, and reach for let only when a value genuinely reassigns.

Ask Codex about JavaScript →
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Low
⚡ Quick Fix
Add process.on('unhandledRejection', ...) in Node.js entry point and window.addEventListener('unhandledrejection', ...) in browser to catch and log all unhandled rejections
📦 Applies To
javascript ES2015 web cli
🔗 Prerequisites
🔍 Detection Hints
async function called without await or .catch(); Promise.all() without catch; fire-and-forget async calls in loops
Auto-detectable: ✓ Yes eslint typescript
🤖 AI Agent
Confidence: High False Positives: Low ✗ Manual fix Fix: Low Context: Function Tests: Update
CWE-390


✓ schema.org compliant