Short answer
Fix the error that follows the prefix first, then make sure every async call has a handler: wrap await in try/catch, add .catch() to promise chains, and return promises from then() callbacks so their errors reach the catch at the end. In React, catch inside the async function you call from useEffect or an event handler and set an error state. In Node.js 15 and later an unhandled rejection crashes the process by default, so add the missing catch rather than silencing it.
Why the rejection is not handled, and the fix
01
An await without try/catch
An async function that awaits a failing call rejects its own promise. If the caller does not await it inside try/catch (or call .catch()), the rejection is unhandled. Event handlers and useEffect callbacks are common places for this, because nothing awaits them.
useEffect(() => { async function load() { try { const res = await fetch('/api/me'); if (!res.ok) throw new Error(`HTTP ${res.status}`); setUser(await res.json()); } catch (err) { setError(err.message); } } load(); }, []);02
A promise started but not returned
“It is important to always return promises from then callbacks, even if the promise always resolves to undefined.” MDN, Using promises
Inside a then() callback, a promise that is started but not returned is cut off from the chain, so the .catch() at the end never sees its error. Return it, or switch to async/await so the flow is easier to follow.
// 🔴 the inner promise is floating save().then(() => { sendEmail(); }).catch(report); // ✅ returned, so its error reaches catch save().then(() => sendEmail()).catch(report);03
Node.js now crashes on unhandled rejections
“v15.0.0 Changed default mode to throw.” Node.js, Command-line API: --unhandled-rejections
Since Node.js 15, an unhandled rejection is raised as an uncaught exception and stops the process, where older versions only printed a warning. Code that “worked” on Node 14 can start crashing after an upgrade. Add the missing catch; use a process-level handler only to log and exit cleanly, not to keep running in an unknown state.
process.on('unhandledRejection', (reason) => { console.error('Unhandled rejection:', reason); process.exit(1); });04
Errors you want reported, not hidden
“The unhandledrejection event is sent to the global scope of a script when a JavaScript Promise that has no rejection handler is rejected” MDN, Window: unhandledrejection event
A global unhandledrejection listener in the browser is useful for sending errors to your monitoring tool, but it does not fix the code path that failed. Use it for reporting, and still handle errors where the user needs feedback, such as a failed save. In Chrome, Uncaught (in promise) Error: A listener indicated an asynchronous response... comes from a browser extension, not your site: test in a window without extensions.
window.addEventListener('unhandledrejection', (event) => { sendToMonitoring(event.reason); });
Checked against the vendor’s docs on : MDN: Window: unhandledrejection event; MDN: Using promises (error handling, returning promises); Node.js: Command-line API (--unhandled-rejections).
Rather hand it over?
Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.
- from $450App Fix TicketOne reproducible bug in an existing mobile or web app, diagnosed and fixed.See scope and start
- from $450AI-Built App RescueA Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.See scope and start
Related: “Unexpected token < in JSON” · Supabase “Failed to fetch” in a published app · ECONNREFUSED: connection refused