OrchardCMS/OrchardCore · error · InvalidOperationException
Can't resolve a scope on tenant
Error message
Can't resolve a scope on tenant '{Settings.Name}' as the shell context is already terminated What it means
AddRef uses an interlocked compare-exchange loop on _refCount. A negative _refCount marks a terminated shell context (Release terminated it), so any further AddRef attempts throw InvalidOperationException because scopes can no longer be created on a terminated shell.
Solutions
- Do not cache ShellContext across operations; obtain it from the shell host each time so a rebuilt shell is used.
- Guard scope creation with a terminated/shell-running check before calling AddRef.
- Wrap scope creation in try/catch InvalidOperationException and re-resolve a fresh context once.
- Ensure long-running work completes or cancels before triggering tenant rebuild/termination.
Example fix
// before var scope = _cachedShell.AddRef(); // may throw if terminated // after var shell = await _shellHost.GetScopeAsync(shellSettings); using var scope = shell.CreateScope();
Defensive patterns
Strategy: try-catch
Try / catch
try { using var scope = shellContext.CreateScope(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("already terminated")) { shellContext = await _shellHost.GetShellContextAsync(settings); /* retry once */ } Prevention
- Obtain ShellContext per operation from IShellHost, never cache it
- Avoid overlapping tenant rebuilds with scope creation
- Stop/cancel tenant-bound work before terminating its shell
When it happens
Trigger: Calling AddRef (via ShellScope creation) after the ShellContext was terminated by Release, e.g. a concurrent request or background task grabbing a scope while the shell is being unloaded/rebuilt.
Common situations: Race between tenant reload and in-flight code, cached ShellContext references outliving termination, singletons capturing the shell during application shutdown.
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
- Unable to reload the tenant
- Can't resolve a scope on tenant
- Invalid serial number for shell descriptor
- Unexpected shell state for
- The 'Default' tenant can't be removed.
AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13).
Data as JSON: /api/errors/63bb89f615e6d64f.
Report an issue: GitHub.
Appendix: source
Thrown at src/OrchardCore/OrchardCore.Abstractions/Shell/Builders/ShellContext.cs:259
}
internal void AddRef()
{
// The service provider is null if we try to create
// a scope on a disabled shell or already disposed.
if (ServiceProvider is null)
{
throw new InvalidOperationException(
$"Can't resolve a scope on tenant '{Settings.Name}' as it is disabled or disposed");
}
int current;
do
{
current = _refCount;
if (current < 0)
{
throw new InvalidOperationException(
$"Can't resolve a scope on tenant '{Settings.Name}' as the shell context is already terminated");
}
// Try to increment _refCount only if it is not <= -1
}
while (Interlocked.CompareExchange(ref _refCount, current + 1, current) != current);
if (Interlocked.CompareExchange(ref _terminated, 0, 0) != 0)
{
// If terminated, decrement back and throw
Interlocked.Decrement(ref _refCount);
throw new InvalidOperationException(
$"Can't resolve a scope on tenant '{Settings.Name}' as the shell context is already terminated");
}
}
internal bool Release()
{View on GitHub (pinned to 4306c0717f)