angular/angular · error · TypeError

Promise resolved with itself

Error message

Promise resolved with itself

What it means

Thrown by zone.js's patched Promise resolution (promise.ts:144): resolving a promise with the very same promise object creates an unresolvable cycle, so resolvePromise() throws TypeError('Promise resolved with itself'), matching the native spec behavior (ChTypeError).

Source

Thrown at packages/zone.js/lib/common/promise.ts:144

          }
          wasCalled = true;
          wrappedFunction.apply(null, arguments);
        };
      };
    };

    const TYPE_ERROR = 'Promise resolved with itself';
    const CURRENT_TASK_TRACE_SYMBOL = __symbol__('currentTaskTrace');

    // Promise Resolution
    function resolvePromise(
      promise: ZoneAwarePromise<any>,
      state: boolean,
      value: any,
    ): ZoneAwarePromise<any> {
      const onceWrapper = once();
      if (promise === value) {
        throw new TypeError(TYPE_ERROR);
      }
      if ((promise as any)[symbolState] === UNRESOLVED) {
        // should only get value.then once based on promise spec.
        let then: any = null;
        try {
          if (typeof value === 'object' || typeof value === 'function') {
            then = value && value.then;
          }
        } catch (err) {
          onceWrapper(() => {
            resolvePromise(promise, false, err);
          })();
          return promise;
        }
        // if (value instanceof ZoneAwarePromise) {
        if (
          state !== REJECTED &&
          value instanceof ZoneAwarePromise &&

View on GitHub (pinned to 51cb07e980)

Solutions

  1. Resolve with a fresh promise or the underlying value, never the promise itself.
  2. In a Deferred, keep the original promise in a separate field and never pass it to resolve().
  3. Restructure self-referential chains using an explicit loop or a helper like Promise.resolve().then(...).

Example fix

// before
const deferred = {};
deferred.promise = new Promise((res) => { deferred.resolve = res; });
deferred.resolve(deferred.promise); // cycle!

// after
const deferred = {};
deferred.promise = new Promise((res) => { deferred.resolve = res; });
deferred.resolve('done'); // resolve with a value, not the promise
Defensive patterns

Strategy: type-guard

Validate before calling

// Guard resolve() inputs in deferred-style helpers
function safeResolve(promise: Promise<any>, value: any) {
  if (value === promise) throw new TypeError('Refusing to resolve a promise with itself');
  return promise; // caller proceeds to resolve with value
}

Type guard

function isSelfResolution(promise: unknown, value: unknown): boolean { return promise === value; }

Try / catch

try { resolve(maybePromise); } catch (e: any) { if (/resolved with itself/.test(e.message)) { resolve(undefined); /* break the cycle with a real value */ } else throw e; }

Prevention

When it happens

Trigger: resolve(p) called with p === the promise being resolved: e.g. promise.then(() => promise) chains, assigning a Deferred's promise back into its own resolver, or reassigning a variable to a promise that resolves to itself in async refactoring.

Common situations: Hand-rolled deferred wrappers (let p = new Promise(r => ...); p.resolve(p)); retry/polling logic that sets promise = promise.then(...) and then resolves with it; porting Promise A+ style code.

Related errors


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