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

  1. Register a custom IChannelNamespacePredicateProvider in DI that recognizes your predicate's pattern format: builder.Services.AddSingleton<IChannelNamespacePredicateProvider, YourProvider>();
  2. 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.
  3. Ensure AddBroadcastChannel (or the equivalent hosting extension that registers DefaultChannelNamespacePredicateProvider and ConstructorChannelNamespacePredicateProvider) is called during silo configuration.
  4. 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

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


AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13). Data as JSON: /api/errors/d0092456b0bdef5a. Report an issue: GitHub.