dotnet/orleans · error · KeyNotFoundException
Could not find an {nameof(IChannelNamespacePredicate)} for t
Error message
Could not find an {nameof(IChannelNamespacePredicate)} for the pattern "{pattern}". Ensure that a corresponding {nameof(IChannelNamespacePredicateProvider)} is registered What it means
Thrown during ImplicitChannelSubscriberTable.BuildCache when the channel-pattern string from a grain binding is not recognized by any registered IChannelNamespacePredicateProvider. The binding stores only a pattern string; at cache build time the providers must reconstruct an IChannelNamespacePredicate from that string. The built-in providers handle '*' (all namespaces), 'regex:' prefix, 'namespace:' prefix (exact match), and 'ctor:' prefix (reflection-based). Any pattern using an unrecognized format has no provider to interpret it.
Source
Thrown at src/Orleans.BroadcastChannel/SubscriberTable/ImplicitChannelSubscriberTable.cs:89
{
continue;
}
if (!grainBinding.TryGetValue(WellKnownGrainTypeProperties.BroadcastChannelBindingPatternKey, out var pattern))
{
throw new KeyNotFoundException(
$"Channel binding for grain type {binding.GrainType} is missing a \"{WellKnownGrainTypeProperties.BroadcastChannelBindingPatternKey}\" value");
}
IChannelNamespacePredicate? predicate = null;
foreach (var provider in _providers)
{
if (provider.TryGetPredicate(pattern, out predicate)) break;
}
if (predicate is null)
{
throw new KeyNotFoundException(
$"Could not find an {nameof(IChannelNamespacePredicate)} for the pattern \"{pattern}\"."
+ $" Ensure that a corresponding {nameof(IChannelNamespacePredicateProvider)} is registered");
}
if (!grainBinding.TryGetValue(WellKnownGrainTypeProperties.ChannelIdMapperKey, out var mapperName))
{
throw new KeyNotFoundException(
$"Channel binding for grain type {binding.GrainType} is missing a \"{WellKnownGrainTypeProperties.ChannelIdMapperKey}\" value");
}
var channelIdMapper = _serviceProvider.GetKeyedService<IChannelIdMapper>(string.IsNullOrWhiteSpace(mapperName) ? DefaultChannelIdMapper.Name : mapperName);
var subscriber = new BroadcastChannelSubscriber(binding, channelIdMapper!);
newPredicates.Add(new BroadcastChannelSubscriberPredicate(subscriber, predicate));
}
}
return new Cache(version, newPredicates);
}View on GitHub (pinned to fca799fa70)
Solutions
- Register a custom IChannelNamespacePredicateProvider in DI that recognizes your predicate's pattern format: builder.Services.AddSingleton<IChannelNamespacePredicateProvider, YourProvider>();
- Use one of the built-in pattern formats: '*' (all namespaces), 'namespace:<exact>' (exact match), or 'regex:<pattern>' (regex match), which the DefaultChannelNamespacePredicateProvider handles out of the box.
- Ensure AddBroadcastChannel (or the equivalent hosting extension that registers DefaultChannelNamespacePredicateProvider and ConstructorChannelNamespacePredicateProvider) is called during silo configuration.
- If using a custom predicate type, use the ctor: prefix pattern (e.g., 'ctor:MyNamespace.MyPredicate,MyAssembly') which the ConstructorChannelNamespacePredicateProvider resolves via reflection without requiring a custom provider.
Example fix
// before — custom predicate whose pattern no provider recognizes
public class MyCustomPredicate : IChannelNamespacePredicate
{
public string PredicatePattern => "custom:orders"; // no provider handles this
public bool IsMatch(string ns) => ns.StartsWith("orders");
}
[ImplicitChannelSubscription(new MyCustomPredicate())]
public class OrderGrain : Grain, IOrderGrain { } // throws KeyNotFoundException at cache build
// after — register a matching provider in the silo host
public class MyCustomPredicateProvider : IChannelNamespacePredicateProvider
{
public bool TryGetPredicate(string pattern, out IChannelNamespacePredicate? predicate)
{
if (pattern.StartsWith("custom:"))
{
predicate = new MyCustomPredicate();
return true;
}
predicate = null;
return false;
}
}
// in silo host configuration:
builder.Services.AddSingleton<IChannelNamespacePredicateProvider, MyCustomPredicateProvider>(); Defensive patterns
Strategy: validation
Validate before calling
// Validate that at least one registered provider can reconstruct a predicate from the pattern.
static void ValidatePatternHasProvider(
string pattern,
IEnumerable<IChannelNamespacePredicateProvider> providers)
{
foreach (var provider in providers)
{
if (provider.TryGetPredicate(pattern, out _))
return;
}
throw new InvalidOperationException(
$"No registered IChannelNamespacePredicateProvider can handle the pattern '{pattern}'. " +
"Built-in formats: '*', 'namespace:<exact>', 'regex:<pattern>', 'ctor:<type>'. " +
"Register a custom provider if using a non-standard pattern.");
} Prevention
- Use built-in pattern formats ('*', 'namespace:<ns>', 'regex:<pattern>') unless a custom predicate is truly necessary.
- If you create a custom IChannelNamespacePredicate, always register a matching IChannelNamespacePredicateProvider in DI that can reconstruct it from its PredicatePattern.
- Ensure AddBroadcastChannel is called during silo configuration so the default predicate providers are registered.
- Consider the ctor: prefix for custom predicate types — the ConstructorChannelNamespacePredicateProvider handles it without a custom provider.
When it happens
Trigger: A grain binding's channel-pattern string is not parseable by any registered IChannelNamespacePredicateProvider. This commonly happens when [ImplicitChannelSubscription] is constructed with a custom IChannelNamespacePredicate whose PredicatePattern format is not supported by any registered provider. It also occurs if the default providers (DefaultChannelNamespacePredicateProvider, ConstructorChannelNamespacePredicateProvider) were not registered because AddBroadcastChannel or the hosting extension was not called. The error fires at cache build time, which runs on the first publish or at silo startup.
Common situations: A developer creates a custom IChannelNamespacePredicate and passes it to the ImplicitChannelSubscription(IChannelNamespacePredicate) constructor, but forgets to register a matching IChannelNamespacePredicateProvider that can reconstruct the predicate from its pattern string. The AddBroadcastChannel hosting extension was not called on the silo builder, so _providers is empty and no pattern can match. A predicate returns a raw pattern like 'foo.*' without a recognized prefix instead of 'regex:foo.*'.
Related errors
- streamId
- Channel binding for grain type {binding.GrainType} is missin
- Channel binding for grain type {binding.GrainType} is missin
- Unknown Playground:Storage:Provider value '{storageProvider}
- WEBSITE_PRIVATE_PORTS must contain at least one TCP port.
AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13).
Data as JSON: /api/errors/d0092456b0bdef5a.
Report an issue: GitHub.