OrchardCMS/OrchardCore · error · InvalidOperationException

Unexpected shell state for

Error message

Unexpected shell state for {settings.Name}

What it means

CreateShellContextAsync throws InvalidOperationException when the tenant's ShellSettings state does not allow a shell context to be created — the settings are in a state not handled by the factory branches above the throw. This is an internal invariant: the shell state machine reached an unhandled combination.

Solutions

  1. Log settings.Name and its State value to identify which state reached the unhandled branch.
  2. Ensure tenant state changes go through ShellHost APIs instead of mutating ShellSettings directly.
  3. Avoid removing or disabling tenants while traffic is in flight; quiesce requests first.
  4. Retry after the concurrent state transition completes — this is often a race, not a persistent condition.
Defensive patterns

Strategy: try-catch

Validate before calling

// Inspect the tenant state before requesting a shell context
if (settings.State is not (TenantState.Running or TenantState.Uninitialized or TenantState.Building))
{
    _logger.LogWarning("Tenant {Name} in unexpected state {State}; skipping shell creation.", settings.Name, settings.State);
    return;
}

Try / catch

try
{
    var context = await _shellHost.GetOrCreateShellContextAsync(settings);
}
catch (InvalidOperationException ex) when (ex.Message.StartsWith("Unexpected shell state"))
{
    _logger.LogWarning(ex, "Shell state race for tenant {Name}; retrying.", settings.Name);
    // retry once after the concurrent transition completes
}

Prevention

When it happens

Trigger: Requesting a shell context (GetOrCreateShellContextAsync) for a tenant whose ShellSettings state is unexpected — e.g. settings exist but their state flag was changed concurrently or the tenant is in an intermediate/degenerate state not covered by the factory logic.

Common situations: Concurrent modification of ShellSettings while requests are being served; a tenant being removed or state-transitioned during request handling; custom code that mutates ShellSettings.State directly.

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


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

Appendix: source

Thrown at src/OrchardCore/OrchardCore/Shell/ShellHost.cs:410

            if (_logger.IsEnabled(LogLevel.Debug))
            {
                _logger.LogDebug("Creating disabled shell context for tenant '{TenantName}'", settings.Name);
            }

            return Task.FromResult(new ShellContext { Settings = settings });
        }
        else if (settings.IsRunning() || settings.IsInitializing())
        {
            if (_logger.IsEnabled(LogLevel.Debug))
            {
                _logger.LogDebug("Creating shell context for tenant '{TenantName}'", settings.Name);
            }

            return _shellContextFactory.CreateShellContextAsync(settings);
        }
        else
        {
            throw new InvalidOperationException("Unexpected shell state for " + settings.Name);
        }
    }

    /// <summary>
    /// Creates a transient shell for the default tenant's setup.
    /// </summary>
    private async Task<ShellContext> CreateSetupContextAsync(ShellSettings defaultSettings)
    {
        if (_logger.IsEnabled(LogLevel.Debug))
        {
            _logger.LogDebug("Creating shell context for root setup.");
        }

        if (defaultSettings is null)
        {
            // Creates a default shell settings based on the configuration.
            defaultSettings = _shellSettingsManager
                .CreateDefaultSettings()

View on GitHub (pinned to 4306c0717f)