OrchardCMS/OrchardCore · error · InvalidOperationException
The 'OrchardCore.SignalR.Azure' and…
Error message
The 'OrchardCore.SignalR.Azure' and 'OrchardCore.SignalR.Redis' features cannot be enabled together.
What it means
Mirror implementation of the backplane guard in the SignalR.Redis module: when its Startup runs, it checks the service collection for the backplane registration marker and throws InvalidOperationException if the Azure backplane feature was already enabled, preventing two SignalR backplanes on one tenant.
Solutions
- Disable either the Redis or the Azure SignalR feature so exactly one backplane is active.
- Remove one of the features from recipe/setup JSON that provisions the tenant.
- Choose the desired backplane up front and document it to prevent toggling both on.
Example fix
// before (tenant features) "OrchardCore.SignalR.Azure", "OrchardCore.SignalR.Redis" // after "OrchardCore.SignalR.Azure"
Defensive patterns
Strategy: validation
Validate before calling
var backplanes = new[] { "OrchardCore.SignalR.Redis", "OrchardCore.SignalR.Azure" }
.Where(f => tenantFeatures.Contains(f)).ToList();
if (backplanes.Count > 1) throw new InvalidOperationException($"Only one backplane allowed, found: {string.Join(',', backplanes)}"); Type guard
const hasSingleBackplane = (fs) => ['OrchardCore.SignalR.Redis','OrchardCore.SignalR.Azure'].filter(f => fs.includes(f)).length === 1;
Try / catch
try {
await enableFeatureAsync("OrchardCore.SignalR.Redis");
} catch (InvalidOperationException ex) when (ex.Message.Contains("cannot be enabled together")) {
logger.LogWarning("Azure backplane already enabled; pick one.");
} Prevention
- Never combine Azure and Redis SignalR features in a tenant or recipe.
- Keep a canonical environment config listing the intended backplane.
- Test tenant provisioning recipes before production rollout.
When it happens
Trigger: Enabling both OrchardCore.SignalR.Redis and OrchardCore.SignalR.Azure features for the same tenant; a recipe enabling both; enabling Redis after Azure in the same request pipeline setup.
Common situations: Admin enables Azure SignalR while Redis is already configured via appsettings-driven feature list; duplicated recipes; test tenants that combined both backplane features.
Related errors
- The 'OrchardCore.SignalR.Azure' and…
- 'UseHierarchicalNamespace' is set to 'true' but the storage…
- Cannot get file info with path
- Cannot get directory info with path
- Cannot get directory content with path
AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13).
Data as JSON: /api/errors/1554468c07196086.
Report an issue: GitHub.
Appendix: source
Thrown at src/OrchardCore.Modules/OrchardCore.SignalR.Redis/Startup.cs:43
return;
}
EnsureNoBackplaneIsRegistered(services);
services
.AddSignalR()
.AddStackExchangeRedis();
services.AddTransient<IConfigureOptions<SignalRRedisOptions>, SignalRRedisOptionsConfiguration>();
}
private static void EnsureNoBackplaneIsRegistered(IServiceCollection services)
{
if (services.Any(descriptor =>
descriptor.IsKeyedService &&
string.Equals(descriptor.ServiceKey as string, BackplaneRegistrationKey, StringComparison.Ordinal)))
{
throw new InvalidOperationException(
$"The '{AzureBackplaneFeature}' and '{RedisBackplaneFeature}' features cannot be enabled together.");
}
services.AddKeyedSingleton<object>(BackplaneRegistrationKey, new object());
}
}
internal sealed class SignalRRedisOptionsConfiguration : IConfigureOptions<SignalRRedisOptions>
{
private readonly RedisOptions _redisOptions;
private readonly string _tenantName;
public SignalRRedisOptionsConfiguration(IOptions<RedisOptions> redisOptions, ShellSettings shellSettings)
{
_redisOptions = redisOptions.Value;
_tenantName = shellSettings.Name;
}
View on GitHub (pinned to 4306c0717f)