OrchardCMS/OrchardCore · error · TypeError
Thenable self-resolution
Error message
Thenable self-resolution
What it means
This TypeError is thrown by jQuery's Promise implementation when a promise resolution handler returns the deferred's own promise — i.e. a promise is resolved with itself. The Promises/A+ spec (section 2.3.1) forbids self-resolution because it creates an unresolvable cycle, so jQuery deliberately fails the deferred with this TypeError instead of hanging forever.
Solutions
- Inspect the .then/.pipe handler on the stack: change it to return a NEW promise/deferred, not the same deferred.promise() it is chained on.
- If resolving a deferred with another promise, verify the value !== the deferred's own promise before resolve().
- Refactor to return the value (or $.Deferred-based promise created inside the handler) rather than the enclosing deferred.
- Where cycles are possible, guard: if (candidate === myPromise) { throw new TypeError('self-resolution'); } before resolving.
Example fix
// before
function run() {
const d = $.Deferred();
d.then(() => d.promise()); // TypeError: Thenable self-resolution
return d.promise();
}
// after
function run() {
return $.Deferred(async (d) => {
const result = await step();
d.resolve(result); // resolve with a value or a DIFFERENT promise
}).promise();
} Defensive patterns
Strategy: type-guard
Validate before calling
function safeResolve(d, value) {
if (value === d.promise()) throw new TypeError('Cannot resolve deferred with its own promise');
d.resolve(value);
} Type guard
function isSelfResolution(d, value) { return value != null && (typeof value === 'object' || typeof value === 'function') && typeof value.then === 'function' && value === d.promise(); } Try / catch
promise.then(handler).catch(function (e) { if (e instanceof TypeError && e.message === 'Thenable self-resolution') { return rebuildChain(); } throw e; }); Prevention
- Never return the same deferred.promise() from a handler attached to that promise.
- Create a fresh Deferred per logical operation instead of reusing module-level deferreds.
- When resolving with a thenable, check it is not the target promise itself.
- Favor async/await with native Promises, which surface self-resolution consistently.
When it happens
Trigger: Inside a .then()/.pipe() handler (or Deferred resolution chain), returning the same deferred.promise() object that is being resolved — e.g. `return d.promise()` from a handler attached to `d.promise()` itself, or resolving a deferred with its own promise.
Common situations: Chaining retries where a handler mistakenly returns the original deferred instead of a new one; recursive wrapper functions that accidentally return the outer promise; converting callback code to promises and reusing a single module-level deferred; mistakenly returning `arguments.callee`-style same-promise from .then.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Thenable self-resolution
- Thenable self-resolution
- Thenable self-resolution
- Thenable self-resolution
- Thenable self-resolution
AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13).
Data as JSON: /api/errors/13b31a871a7e9314.
Report an issue: GitHub.
Appendix: source
Thrown at src/OrchardCore.Modules/OrchardCore.Resources/wwwroot/Vendor/jquery-3.5.1/jquery.js:3767
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)