zloirock/core-js · error · TypeError

Promise can't be resolved itself

Error message

Promise can't be resolved itself

What it means

core-js's Promise polyfill rejects a promise being resolved with its own fulfillment value/thenable wrapper. Per spec, resolving a promise with itself would create an unresolvable cycle, so internalResolve detects state.facade === value and throws a TypeError. This can also surface via Promise.all/then chains that feed a promise back into itself.

Source

Thrown at packages/core-js/modules/es.promise.constructor.js:173

    fn(state, value, unwrap);
  };
};

var internalReject = function (state, value, unwrap) {
  if (state.done) return;
  state.done = true;
  if (unwrap) state = unwrap;
  state.value = value;
  state.state = REJECTED;
  notify(state, true);
};

var internalResolve = function (state, value, unwrap) {
  if (state.done) return;
  state.done = true;
  if (unwrap) state = unwrap;
  try {
    if (state.facade === value) throw new TypeError("Promise can't be resolved itself");
    var then = isThenable(value);
    if (then) {
      microtask(function () {
        var wrapper = { done: false };
        try {
          call(then, value,
            bind(internalResolve, wrapper, state),
            bind(internalReject, wrapper, state)
          );
        } catch (error) {
          internalReject(wrapper, error, state);
        }
      });
    } else {
      state.value = value;
      state.state = FULFILLED;
      notify(state, false);
    }

View on GitHub (pinned to 84e45fba09)

Solutions

  1. Never resolve a promise with itself; verify the value passed to resolve() is not the promise variable (rename variables to avoid shadowing).
  2. Resolve with the underlying value instead of the promise: fetch the awaited data and pass that.
  3. Break the circular reference: if a thenable references its container, unwrap it before resolving.
  4. If using polyfilled Promise in tests, replicate the cycle check — it's spec behavior, not a bug.
  5. Return the promise from the executor rather than resolving it (let the chain propagate).

Example fix

// before
const p = new Promise((resolve) => {
  doWork((err, result) => resolve(result ?? p)); // TypeError when result missing
});
// after
const p = new Promise((resolve) => {
  doWork((err, result) => resolve(result));
});
Defensive patterns

Strategy: validation

Validate before calling

function safeResolve(promiseRef, value) {
  if (value === promiseRef || (value && typeof value.then === 'function' && value === promiseRef)) {
    throw new TypeError('Cannot resolve a promise with itself');
  }
}
// call before: safeResolve(p, candidateValue)

Type guard

function isSelfResolution(p, v) { return v === p; }
// usage: if (!isSelfResolution(p, value)) resolve(value);

Try / catch

try {
  await p;
} catch (e) {
  if (e instanceof TypeError && /resolved itself|Chaining cycle/.test(e.message)) {
    // break the cycle: resolve with a derived value instead
  } else throw e;
}

Prevention

When it happens

Trigger: const p = new Promise(res => res(p)); — resolving a promise with itself; promise.then(resolve) wired so the resolution value is the same promise; circular thenable structures where a promise's fulfillment value is the promise object; polyfilled Promise.all/settled input arrays containing the aggregate promise itself.

Common situations: Recursive async code caching a promise and passing it to its own resolve callback; refactoring a callback API where the resolve reference and the returned promise are the same variable; Promise.all(promiseItself) by mistake; using a polyfilled Promise (older browsers) where native engines may report 'Chaining cycle detected'.

Related errors


AI-assisted analysis of zloirock/core-js@84e45fba09 (2026-08-30). Data as JSON: /api/errors/685a68686adb9a66. Report an issue: GitHub.