{"record":{"id":"e7fe4481040752be","repo":"OrchardCMS/OrchardCore","slug":"the-tenant-settings-name-can-t-be-removed-as-it-is-neither","errorCode":null,"errorMessage":"The tenant '{settings.Name}' can't be removed as it is neither uninitialized nor disabled.","messagePattern":"The tenant '(.+?)' can't be removed as it is neither uninitialized nor disabled\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/OrchardCore/OrchardCore/Shell/ShellHost.cs","lineNumber":523,"sourceCode":"    /// Note: A disabled shell still in use will be released by its last scope, and keeping it in the list\n    /// prevents a consumer from creating a new one that would have a null service provider.\n    /// </summary>\n    private bool CanReleaseShell(ShellSettings settings) => !settings.IsDisabled() || !IsShellActive(settings);\n\n    /// <summary>\n    /// Checks if a shell can be removed, throws an exception if the shell is neither uninitialized nor disabled.\n    /// </summary>\n    private void CheckCanRemoveShell(ShellSettings settings)\n    {\n        if (settings.IsDefaultShell())\n        {\n            throw new InvalidOperationException($\"The '{ShellSettings.DefaultShellName}' tenant can't be removed.\");\n        }\n\n        // A disabled shell may be still in use in at least one active scope.\n        if (!settings.IsRemovable() || IsShellActive(settings))\n        {\n            throw new InvalidOperationException(\n                $\"The tenant '{settings.Name}' can't be removed as it is neither uninitialized nor disabled.\");\n        }\n    }\n\n    /// <summary>\n    /// Whether or not a shell is in use in at least one active scope.\n    /// </summary>\n    private bool IsShellActive(ShellSettings settings) =>\n        settings is { Name: not null } &&\n        _shellContexts.TryGetValue(settings.Name, out var context) &&\n        context.IsActive();\n\n    public void Dispose()\n    {\n        foreach (var shell in ListShellContexts())\n        {\n            shell.Dispose();\n        }","sourceCodeStart":505,"sourceCodeEnd":541,"githubUrl":"https://github.com/OrchardCMS/OrchardCore/blob/4306c0717fe573f6fca1b4955909ddab6a192807/src/OrchardCore/OrchardCore/Shell/ShellHost.cs#L505-L541","documentation":"CheckCanRemoveShell throws InvalidOperationException when the target tenant is not removable: it is neither uninitialized nor disabled, or a shell for it is still active in at least one scope. Only uninitialized or disabled, inactive tenants may be deleted.","triggerScenarios":"Calling RemoveShellSettingsAsync/RemoveShellContextAsync for a running (enabled and started) tenant, or for a disabled tenant whose shell context is still held by active scopes.","commonSituations":"Deleting a live tenant from a script without disabling it first; removing a tenant that was just disabled but still serves in-flight requests; UI logic racing with active request scopes holding the shell.","solutions":["Disable the tenant first and wait for it to become inactive, then remove it.","Retry after in-flight requests complete — active scopes release the shell when requests finish.","Check settings.IsRemovable() and ensure no active scopes exist before attempting removal."],"exampleFix":"// before\nawait _shellHost.RemoveShellSettingsAsync(settings);\n// after\nsettings.State = TenantState.Disabled;\nawait _shellHost.UpdateShellSettingsAsync(settings);\n// ensure no active scopes, then:\nawait _shellHost.RemoveShellSettingsAsync(settings);","handlingStrategy":"validation","validationCode":"if (!settings.IsRemovable() || settings.Name == ShellSettings.DefaultShellName)\n{\n    // disable first, then remove after in-flight requests drain\n    settings.State = TenantState.Disabled;\n    await shellHost.UpdateShellSettingsAsync(settings);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Call settings.IsRemovable() before RemoveShellSettingsAsync/RemoveShellContextAsync.","Disable the tenant and let active scopes drain before deletion.","Avoid removing tenants while requests against them may still be executing."],"tags":["multi-tenancy","tenants","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"4306c0717fe573f6fca1b4955909ddab6a192807","analyzedAt":"2026-09-13T17:41:05.024Z","contentChangedAt":"2026-09-13T17:41:05.024Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}