angular/angular · error · Error
Uncaught (in promise): ${readableObjectToString(value)}${val
Error message
Uncaught (in promise): ${readableObjectToString(value)}${value && value.stack ? '\n' + value.stack : ''} What it means
Not a thrown error you catch, but zone.js's unhandled-rejection reporting: when a rejected ZoneAwarePromise finishes its callback queue with no rejection handler, zone.js builds a readable Error ('Uncaught (in promise): ' + value) to attach stack info and routes it to Zone.onUnhandledError / window.onerror. The property throwOriginal may be set to surface the raw rejection value instead.
Source
Thrown at packages/zone.js/lib/common/promise.ts:225
configurable: true,
enumerable: false,
writable: true,
value: trace,
});
}
}
for (let i = 0; i < queue.length;) {
scheduleResolveOrReject(promise, queue[i++], queue[i++], queue[i++], queue[i++]);
}
if (queue.length == 0 && state == REJECTED) {
(promise as any)[symbolState] = REJECTED_NO_CATCH;
let uncaughtPromiseError = value;
try {
// Here we throws a new Error to print more readable error log
// and if the value is not an error, zone.js builds an `Error`
// Object here to attach the stack information.
throw new Error(
'Uncaught (in promise): ' +
readableObjectToString(value) +
(value && value.stack ? '\n' + value.stack : ''),
);
} catch (err) {
uncaughtPromiseError = err;
}
if (isDisableWrappingUncaughtPromiseRejection) {
// If disable wrapping uncaught promise reject
// use the value instead of wrapping it.
uncaughtPromiseError.throwOriginal = true;
}
uncaughtPromiseError.rejection = value;
uncaughtPromiseError.promise = promise;
uncaughtPromiseError.zone = Zone.current;
uncaughtPromiseError.task = Zone.currentTask!;
_uncaughtPromiseErrors.push(uncaughtPromiseError);
api.scheduleMicroTask(); // to make sure that it is runningView on GitHub (pinned to 51cb07e980)
Solutions
- Attach .catch(...) (or try/catch around await) to every promise that can reject.
- For observables, provide an error handler to subscribe: source.subscribe(next, err => ...).
- Register a global handler (window.addEventListener('unhandledrejection', ...) or Zone's onUnhandledError via ERROR_COOPERATIVE_GLOBAL_SCHEDULING-style config) to log and triage.
- Set global[__zone_symbol__ignoreConsoleErrorUncaughtError] = true only as a temporary suppress, then fix the root causes.
Example fix
// before
this.http.get('/api/heroes').toPromise(); // rejection unhandled
// after
try { const heroes = await this.http.get('/api/heroes').toPromise(); }
catch (e) { this.logger.error(e); } Defensive patterns
Strategy: try-catch
Try / catch
// Surface unhandled rejections globally for triage instead of letting them vanish
window.addEventListener('unhandledrejection', (event) => {
logger.error('Unhandled rejection:', event.reason);
}); Prevention
- Attach .catch or try/catch-await to every promise you create or call.
- Enable strict TypeScript checks and lint rules (e.g. no-floating-promises) to catch unhandled promises at build time.
- Treat every 'Uncaught (in promise)' in CI logs as a failing signal.
When it happens
Trigger: A promise rejects and no .catch/onRejection is attached before the microtask queue drains (symbolState becomes REJECTED_NO_CATCH): missing .catch on fetch calls, async functions invoked without await/catch, fire-and-forget tasks.
Common situations: Angular apps calling this.http.get(...).subscribe-less or promise-based APIs without error handlers; test environments reporting 'Uncaught (in promise)' in console; regressions where a .catch was dropped during refactor.
Related errors
- Zone.js has detected that ZoneAwarePromise `(window|global).
- Cannot assign to read only property '${prop}' of ${obj}
- Promise resolved with itself
- Must be an instanceof Promise.
- NG0914
AI-assisted analysis of angular/angular@51cb07e980 (2026-08-22).
Data as JSON: /api/errors/6a3f7d08823377f6.
Report an issue: GitHub.