OrchardCMS/OrchardCore · error · TypeError

Thenable self-resolution

Error message

Thenable self-resolution

What it means

jQuery's promise implementation throws this TypeError during promise resolution when a resolved/rejected value is a thenable that is the promise itself, i.e. a promise resolved with itself. Per Promises/A+ 2.3.1, self-resolution would create an infinite resolution loop, so it must be rejected with this TypeError.

Solutions

  1. Find the resolve/then call that passes the promise its own value; resolve with the actual data instead (deferred.resolve(data)).
  2. In .then() handlers, return the computed value or a new/different promise, never the same promise object.
  3. If you need the settled value of the same chain, capture it in a separate variable or use an inner promise rather than returning the outer one.
  4. Refactor cyclic deferred usage into async/await, where self-await still throws but is easier to spot (TypeError: Chaining cycle detected).

Example fix

// before
var d = $.Deferred();
function load() {
  d.resolve(d.promise()); // self-resolution
  return d.promise();
}

// after
var d = $.Deferred();
function load() {
  d.resolve(fetchData()); // resolve with actual value or another promise
  return d.promise();
}
Defensive patterns

Strategy: type-guard

Validate before calling

function safeResolve(deferred, value) {
  if (value === deferred || value === deferred.promise()) {
    throw new TypeError('Attempted to resolve a deferred with itself');
  }
  deferred.resolve(value);
}

Type guard

function isSelfResolution(deferred, value) { return value != null && (value === deferred || value === deferred.promise()); }

Try / catch

p.catch(function (e) {
  if (e instanceof TypeError && /Thenable self-resolution/.test(e.message)) {
    // handle cyclic promise: recover or report
  } else { throw e; }
});

Prevention

When it happens

Trigger: Calling deferred.resolve(deferred.promise()) or resolving a jQuery promise with itself; inside a .then() handler returning the same promise object the handler belongs to; cyclic chains like p.then(function(){ return p; }); patterns where a deferred is resolved with its own promise in async recursion.

Common situations: Recursive async code that caches its own promise and passes it back as the success value; refactored code where a variable accidentally references the same deferred/promise; misused .then() chains where the return value of the callback is the outer promise rather than a plain value or a different thenable.

Related errors


AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13). Data as JSON: /api/errors/442abe58b763a145. Report an issue: GitHub.

Appendix: source

Thrown at src/OrchardCore.Modules/OrchardCore.Resources/wwwroot/Vendor/jquery-3.6.0/jquery.js:3771

						return function() {
							var that = this,
								args = arguments,
								mightThrow = function() {
									var returned, then;

									// Support: Promises/A+ section 2.3.3.3.3
									// https://promisesaplus.com/#point-59
									// Ignore double-resolution attempts
									if ( depth < maxDepth ) {
										return;
									}

									returned = handler.apply( that, args );

									// Support: Promises/A+ section 2.3.1
									// https://promisesaplus.com/#point-48
									if ( returned === deferred.promise() ) {
										throw new TypeError( "Thenable self-resolution" );
									}

									// Support: Promises/A+ sections 2.3.3.1, 3.5
									// https://promisesaplus.com/#point-54
									// https://promisesaplus.com/#point-75
									// Retrieve `then` only once
									then = returned &&

										// Support: Promises/A+ section 2.3.4
										// https://promisesaplus.com/#point-64
										// Only check objects and functions for thenability
										( typeof returned === "object" ||
											typeof returned === "function" ) &&
										returned.then;

									// Handle a returned thenable
									if ( isFunction( then ) ) {

View on GitHub (pinned to 4306c0717f)