{"record":{"id":"d0092456b0bdef5a","repo":"dotnet/orleans","slug":"could-not-find-an-nameof-ichannelnamespacepredica","errorCode":null,"errorMessage":"Could not find an {nameof(IChannelNamespacePredicate)} for the pattern \"{pattern}\". Ensure that a corresponding {nameof(IChannelNamespacePredicateProvider)} is registered","messagePattern":"Could not find an (.+?) for the pattern \"(.+?)\"\\. Ensure that a corresponding (.+?) is registered","errorType":"exception","errorClass":"KeyNotFoundException","httpStatus":null,"severity":"error","filePath":"src/Orleans.BroadcastChannel/SubscriberTable/ImplicitChannelSubscriberTable.cs","lineNumber":89,"sourceCode":"                    {\n                        continue;\n                    }\n\n                    if (!grainBinding.TryGetValue(WellKnownGrainTypeProperties.BroadcastChannelBindingPatternKey, out var pattern))\n                    {\n                        throw new KeyNotFoundException(\n                           $\"Channel binding for grain type {binding.GrainType} is missing a \\\"{WellKnownGrainTypeProperties.BroadcastChannelBindingPatternKey}\\\" value\");\n                    }\n\n                    IChannelNamespacePredicate? predicate = null;\n                    foreach (var provider in _providers)\n                    {\n                        if (provider.TryGetPredicate(pattern, out predicate)) break;\n                    }\n\n                    if (predicate is null)\n                    {\n                        throw new KeyNotFoundException(\n                            $\"Could not find an {nameof(IChannelNamespacePredicate)} for the pattern \\\"{pattern}\\\".\"\n                            + $\" Ensure that a corresponding {nameof(IChannelNamespacePredicateProvider)} is registered\");\n                    }\n\n                    if (!grainBinding.TryGetValue(WellKnownGrainTypeProperties.ChannelIdMapperKey, out var mapperName))\n                    {\n                        throw new KeyNotFoundException(\n                           $\"Channel binding for grain type {binding.GrainType} is missing a \\\"{WellKnownGrainTypeProperties.ChannelIdMapperKey}\\\" value\");\n                    }\n\n                    var channelIdMapper = _serviceProvider.GetKeyedService<IChannelIdMapper>(string.IsNullOrWhiteSpace(mapperName) ? DefaultChannelIdMapper.Name : mapperName);\n                    var subscriber = new BroadcastChannelSubscriber(binding, channelIdMapper!);\n                    newPredicates.Add(new BroadcastChannelSubscriberPredicate(subscriber, predicate));\n                }\n            }\n\n            return new Cache(version, newPredicates);\n        }","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/dotnet/orleans/blob/fca799fa70ecb6ad975224271703ca43221f58de/src/Orleans.BroadcastChannel/SubscriberTable/ImplicitChannelSubscriberTable.cs#L71-L107","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.*'.","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."],"exampleFix":"// before — custom predicate whose pattern no provider recognizes\npublic class MyCustomPredicate : IChannelNamespacePredicate\n{\n    public string PredicatePattern => \"custom:orders\"; // no provider handles this\n    public bool IsMatch(string ns) => ns.StartsWith(\"orders\");\n}\n\n[ImplicitChannelSubscription(new MyCustomPredicate())]\npublic class OrderGrain : Grain, IOrderGrain { } // throws KeyNotFoundException at cache build\n\n// after — register a matching provider in the silo host\npublic class MyCustomPredicateProvider : IChannelNamespacePredicateProvider\n{\n    public bool TryGetPredicate(string pattern, out IChannelNamespacePredicate? predicate)\n    {\n        if (pattern.StartsWith(\"custom:\"))\n        {\n            predicate = new MyCustomPredicate();\n            return true;\n        }\n        predicate = null;\n        return false;\n    }\n}\n\n// in silo host configuration:\nbuilder.Services.AddSingleton<IChannelNamespacePredicateProvider, MyCustomPredicateProvider>();","handlingStrategy":"validation","validationCode":"// Validate that at least one registered provider can reconstruct a predicate from the pattern.\nstatic void ValidatePatternHasProvider(\n    string pattern,\n    IEnumerable<IChannelNamespacePredicateProvider> providers)\n{\n    foreach (var provider in providers)\n    {\n        if (provider.TryGetPredicate(pattern, out _))\n            return;\n    }\n    throw new InvalidOperationException(\n        $\"No registered IChannelNamespacePredicateProvider can handle the pattern '{pattern}'. \" +\n        \"Built-in formats: '*', 'namespace:<exact>', 'regex:<pattern>', 'ctor:<type>'. \" +\n        \"Register a custom provider if using a non-standard pattern.\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["broadcast-channel","namespace-predicate","configuration","di-registration"],"backgroundTag":null,"analyzedSha":"fca799fa70ecb6ad975224271703ca43221f58de","analyzedAt":"2026-08-13T19:55:57.938Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}