{"record":{"id":"474e6efd7a137194","repo":"dotnet/yarp","slug":"one-or-more-exceptions-thrown-by-resourceinformerc","errorCode":null,"errorMessage":"One or more exceptions thrown by ResourceInformerCallback.","messagePattern":"One or more exceptions thrown by ResourceInformerCallback\\.","errorType":"exception","errorClass":"AggregateException","httpStatus":null,"severity":"error","filePath":"src/Kubernetes.Controller/Client/ResourceInformer.cs","lineNumber":426,"sourceCode":"    {\n\n        List<Exception> innerExceptions = default;\n        foreach (var registration in _registrations)\n        {\n            try\n            {\n                registration.Callback.Invoke(eventType, resource);\n            }\n            catch (Exception innerException)\n            {\n                innerExceptions ??= new List<Exception>();\n                innerExceptions.Add(innerException);\n            }\n        }\n\n        if (innerExceptions is not null)\n        {\n            throw new AggregateException(\"One or more exceptions thrown by ResourceInformerCallback.\", innerExceptions);\n        }\n    }\n\n    internal class Registration : IResourceInformerRegistration\n    {\n        private bool _disposedValue;\n\n        public Registration(ResourceInformer<TResource, TListResource> resourceInformer, ResourceInformerCallback<TResource> callback)\n        {\n            ResourceInformer = resourceInformer;\n            Callback = callback;\n            lock (resourceInformer._sync)\n            {\n                resourceInformer._registrations = resourceInformer._registrations.Add(this);\n            }\n        }\n\n        ~Registration()","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/dotnet/yarp/blob/bd11867bee7df522e7fd3effb08a9c85fd616908/src/Kubernetes.Controller/Client/ResourceInformer.cs#L408-L444","documentation":"Thrown as an AggregateException by ResourceInformer after it has dispatched resource events to all registered ResourceInformerCallback delegates. If one or more callbacks throw, each exception is collected and re-thrown as a single aggregate so no callback failure is silently swallowed. This is part of the Kubernetes controller informer loop that watches cluster resources.","triggerScenarios":"One or more IResourceInformerRegistration callbacks throw an exception during event dispatch (WatchAdd/WatchModify/WatchDelete). The informer collects all such exceptions across registered callbacks for a given event dispatch cycle and throws the aggregate.","commonSituations":"A callback has an unhandled bug (null deref, invalid cast on the resource object). A callback calls an external API that fails. Callback logic assumes a resource shape that changed across Kubernetes API versions.","solutions":["Inspect the AggregateException.InnerExceptions to find the root cause from the failing callback.","Wrap the callback body in try/catch to handle expected failures locally instead of letting them propagate.","Fix the bug in the callback implementation identified by the inner exception.","Add logging inside the callback to capture per-event context before failure."],"exampleFix":"// before — callback throws\ninformer.Register((eventType, resource) =>\n{\n    var name = resource.Metadata.Name; // NullReferenceException if Metadata null\n});\n// after — guard inside callback\ninformer.Register((eventType, resource) =>\n{\n    try\n    {\n        var name = resource.Metadata?.Name ?? \"unknown\";\n        // process\n    }\n    catch (Exception ex)\n    {\n        _logger.LogError(ex, \"Callback failed for {EventType}\", eventType);\n    }\n});","handlingStrategy":"try-catch","validationCode":"// n/a — cannot validate callback behavior statically; guard at registration time\nif (callback is null) throw new ArgumentNullException(nameof(callback));","typeGuard":"// n/a","tryCatchPattern":"try { await informerLoopAsync; }\ncatch (AggregateException ax)\n{\n    foreach (var inner in ax.InnerExceptions)\n        logger.LogError(inner, \"Informer callback failed\");\n    // decide: continue, restart informer, or terminate\n}","preventionTips":["Never let exceptions escape a ResourceInformerCallback — wrap the body in try/catch.","Log per-event context inside callbacks for diagnosis.","Keep callbacks fast and side-effect-free; offload heavy work to a queue."],"tags":["kubernetes","informer","callback","aggregate-exception","event-dispatch"],"backgroundTag":null,"analyzedSha":"bd11867bee7df522e7fd3effb08a9c85fd616908","analyzedAt":"2026-08-13T21:29:49.359Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}