{"record":{"id":"490671364d53562a","repo":"dotnet/wpf","slug":"sr-automation-recursivepubliccall","errorCode":null,"errorMessage":"SR.Automation_RecursivePublicCall","messagePattern":"SR\\.Automation_RecursivePublicCall","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Automation/SynchronizedInputAdaptor.cs","lineNumber":46,"sourceCode":"        /// <param name=\"inputType\"> Synchronized input type</param>\n        void ISynchronizedInputProvider.StartListening(SynchronizedInputType inputType)\n        {\n            if (inputType != SynchronizedInputType.KeyDown &&\n                inputType != SynchronizedInputType.KeyUp &&\n                inputType != SynchronizedInputType.MouseLeftButtonDown &&\n                inputType != SynchronizedInputType.MouseLeftButtonUp &&\n                inputType != SynchronizedInputType.MouseRightButtonDown &&\n                inputType != SynchronizedInputType.MouseRightButtonUp)\n            {\n                throw new ArgumentException(SR.Format(SR.Automation_InvalidSynchronizedInputType, inputType));\n            }\n            \n            UIElement e = _owner as UIElement;\n            if (e != null)\n            {\n                if (!e.StartListeningSynchronizedInput(inputType))\n                {\n                    throw new InvalidOperationException(SR.Automation_RecursivePublicCall);\n                }\n            }\n            else\n            {\n                ContentElement ce = _owner as ContentElement;\n                if (ce != null)\n                {\n                    if (!ce.StartListeningSynchronizedInput(inputType))\n                    {\n                        throw new InvalidOperationException(SR.Automation_RecursivePublicCall);\n                    }\n                }\n                else\n                {\n                    UIElement3D e3D = (UIElement3D)_owner;\n                    if (!e3D.StartListeningSynchronizedInput(inputType))\n                    {\n                        throw new InvalidOperationException(SR.Automation_RecursivePublicCall);","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Automation/SynchronizedInputAdaptor.cs#L28-L64","documentation":"When the SynchronizedInputAdaptor's owner is a UIElement, StartListening forwards to UIElement.StartListeningSynchronizedInput. If that returns false the element is already processing a synchronized-input session (a recursive public automation call is in progress), so the adaptor throws InvalidOperationException with SR.Automation_RecursivePublicCall.","triggerScenarios":"Calling StartListening on a UIElement whose synchronized-input tracking indicates an active session — i.e. StartListening (or a re-entrant automation call) was invoked while a previous Start/CancelListening session was still open on the same element.","commonSituations":"Re-entrant automation calls during an active synchronized-input session; a UIA client issuing StartListening twice without CancelListening or StopListening in between; nested provider calls triggered from within input event handling.","solutions":["Ensure each StartListening is paired with CancelListening/StopListening before starting a new session.","Guard client code against calling StartListening twice concurrently on the same element.","Track session state (bool flag) around synchronized-input usage and serialize calls.","In the app, avoid raising automation events from inside synchronized-input event handlers that could re-enter StartListening."],"exampleFix":"// before\nprovider.StartListening(type);\nprovider.StartListening(type); // throws: session already active\n// after\nprovider.StartListening(type);\ntry { /* consume InputReachedTarget/Other/Discarded */ }\nfinally { provider.CancelListening(); }","handlingStrategy":"try-catch","validationCode":"// track session state to avoid overlapping StartListening calls\nif (synchronizedInputSessionActive) throw new InvalidOperationException(\"session already active\");","typeGuard":"bool CanStartSession(bool sessionActive) => !sessionActive;","tryCatchPattern":"try\n{\n    provider.StartListening(type);\n    synchronizedInputSessionActive = true;\n}\ncatch (InvalidOperationException)\n{\n    provider.CancelListening(); // end stale session, then retry\n    provider.StartListening(type);\n}","preventionTips":["Always pair StartListening with CancelListening/StopListening","Never call StartListening twice without ending the prior session","Avoid re-entrant automation calls from within synchronized-input handlers","Wait for InputReachedTarget/InputDiscarded events before starting a new session"],"tags":["wpf","ui-automation","invalid-operation","reentrancy","synchronized-input"],"backgroundTag":"invalid-state-transition","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"}