{"record":{"id":"91d72241b68d5950","repo":"dotnet/wpf","slug":"sr-toomanyroutedevents","errorCode":null,"errorMessage":"SR.TooManyRoutedEvents","messagePattern":"SR\\.TooManyRoutedEvents","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/GlobalEventManager.cs","lineNumber":439,"sourceCode":"\n        #endregion Operations\n\n        #region Global Index for RoutedEvent and EventPrivateKey\n\n        /// <summary>\n        /// Increments the global counter for <see cref=\"RoutedEvent\"/> and <see cref=\"EventPrivateKey\"/> storage.\n        /// </summary>\n        /// <returns>Globally unique index for the event within the application.</returns>\n        /// <exception cref=\"InvalidOperationException\">Thrown in case the index is bigger than <see cref=\"int.MaxValue\"/>.</exception>\n        internal static int GetNextAvailableGlobalIndex()\n        {\n            // Prevent GlobalIndex from overflow. RoutedEvents are meant to be static members and are to be registered \n            // only via static constructors. However there is no cheap way of ensuring this, without having to do a stack walk. Hence \n            // concievably people could register RoutedEvents via instance methods and therefore cause the GlobalIndex to \n            // overflow. This check will explicitly catch this error, instead of silently malfuntioning.\n            uint newIndex = Interlocked.Increment(ref s_globalEventIndex);\n            if (newIndex >= int.MaxValue)\n                throw new InvalidOperationException(SR.TooManyRoutedEvents);\n\n            return (int)newIndex;\n        }\n\n        /// <summary>\n        /// Access must be done atomically, currently only accessed via <see cref=\"GetNextAvailableGlobalIndex\"/> method.\n        /// </summary>\n        private static uint s_globalEventIndex = uint.MinValue;\n\n        #endregion\n\n        #region Data\n\n        // This is an efficient  Hashtable of ItemLists keyed on DType\n        // Each ItemList holds the registered RoutedEvents for that OwnerType\n        private static DTypeMap _dTypedRoutedEventList = new DTypeMap(10); // Initialization sizes based on typical MSN scenario\n        \n        // This is a Hashtable of ItemLists keyed on OwnerType","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/GlobalEventManager.cs#L421-L457","documentation":"GlobalEventManager.GetNextAvailableGlobalIndex throws InvalidOperationException with SR.TooManyRoutedEvents when the global static counter of registered routed events would overflow int.MaxValue. RoutedEvents are meant to be registered once from static constructors, so the space should never be exhausted in correct usage. The explicit check catches the pathological case of registering routed events from instance code at scale instead of letting the index silently malfunction.","triggerScenarios":"Registering more than ~2.1 billion RoutedEvent instances, typically by calling RoutedEvent.Register (which allocates a new global index) repeatedly from instance methods or per-object code instead of once statically.","commonSituations":"A factory class or data template creating RoutedEvents per instance/per item; a plugin system re-registering events on every load; misuse of EventManager.RegisterRoutedEvent outside static initialization.","solutions":["Register each RoutedEvent once in a static constructor or as a static readonly field and reuse it.","Refactor code that registers events per-instance to share a single static RoutedEvent per event identity.","Audit dynamic registration paths (factories, plugins) and cache RoutedEvents by name/ownerType."],"exampleFix":"// before\npublic RoutedEvent GetEvent() => RoutedEvent.Register(\"Ev\", RoutingStrategy.Bubble, typeof(EventHandler), typeof(MyClass)); // new index every call\n// after\nprivate static readonly RoutedEvent EvEvent = RoutedEvent.Register(\"Ev\", RoutingStrategy.Bubble, typeof(EventHandler), typeof(MyClass));\npublic RoutedEvent GetEvent() => EvEvent;","handlingStrategy":"validation","validationCode":"// Never register routed events per-instance; hoist to a static field:\nprivate static readonly RoutedEvent EvEvent =\n    RoutedEvent.Register(\"Ev\", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyClass));","typeGuard":null,"tryCatchPattern":"try { var ev = RoutedEvent.Register(name, strategy, handlerType, ownerType); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"TooManyRoutedEvents\")) { /* registration site runs per-instance; fix to static registration */ }","preventionTips":["Declare RoutedEvents only in static constructors or static readonly fields","Cache RoutedEvents in a dictionary keyed by (name, ownerType) for dynamic scenarios","Never call RoutedEvent.Register inside instance methods, factories, or per-item loops"],"tags":["wpf","routed-events","overflow","registration"],"backgroundTag":"internal-invariant-violation","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-22T01:17:13.364Z"}