OrchardCMS/OrchardCore · error · TypeError
Thenable self-resolution
Error message
Thenable self-resolution
What it means
jQuery's Deferred implementation throws this TypeError when a promise handler (an added done/fail/progress/then callback) returns the same deferred's own promise, which would make the promise resolve itself — a cycle forbidden by Promises/A+ (section 2.3.1). jQuery aborts to prevent infinite recursion.
Solutions
- Return a new promise/value from the handler, never the same deferred.promise()
- Return a distinct thenable or plain value to chain properly
- Restructure so the deferred used for resolution is created outside and not returned by its own handlers
- Use native Promises, which reject cycles with 'Chaining cycle detected' instead
Example fix
// before
var d = $.Deferred();
d.then(function () { return d.promise(); }); // TypeError: Thenable self-resolution
// after
var d = $.Deferred();
d.then(function (v) { return v; }); Defensive patterns
Strategy: type-guard
Validate before calling
function returnsSelf(deferred, handler) { return handler && deferred.promise !== undefined; } Type guard
function isSamePromise(returned, deferred) { return returned === deferred.promise(); } Try / catch
try { d.then(handler); } catch (e) { if (e instanceof TypeError && e.message === 'Thenable self-resolution') { console.error('Handler returned its own promise'); } else { throw e; } } Prevention
- Never return deferred.promise() from a handler on that same deferred
- Return plain values or fresh promises from .then handlers
- Prefer native Promises over jQuery Deferreds for new code
- Review refactored promise chains for closure variable self-reference
When it happens
Trigger: Inside a .then/.done handler on a jQuery deferred, returning the same deferred.promise() object, e.g. `d.then(function(){ return d.promise(); })`, or returning a thenable that is the promise itself.
Common situations: Chaining code that accidentally returns the original promise instead of a new one; reusing a deferred variable in a closure inside its own handler; refactored promise chains creating self-referential returns.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 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/144137a3b8d5b363.
Report an issue: GitHub.
Appendix: source
Thrown at src/OrchardCore.Modules/OrchardCore.Resources/wwwroot/Vendor/jquery-3.4.1/jquery.js:3562
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)