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 running

View on GitHub (pinned to 51cb07e980)

Solutions

  1. Attach .catch(...) (or try/catch around await) to every promise that can reject.
  2. For observables, provide an error handler to subscribe: source.subscribe(next, err => ...).
  3. Register a global handler (window.addEventListener('unhandledrejection', ...) or Zone's onUnhandledError via ERROR_COOPERATIVE_GLOBAL_SCHEDULING-style config) to log and triage.
  4. 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

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


AI-assisted analysis of angular/angular@51cb07e980 (2026-08-22). Data as JSON: /api/errors/6a3f7d08823377f6. Report an issue: GitHub.