dotnet/wpf · error · InvalidOperationException
SR.Automation_RecursivePublicCall
Error message
SR.Automation_RecursivePublicCall
What it means
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.
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.
Example fix
// before
provider.StartListening(type);
provider.StartListening(type); // throws: session already active
// after
provider.StartListening(type);
try { /* consume InputReachedTarget/Other/Discarded */ }
finally { provider.CancelListening(); } Defensive patterns
Strategy: try-catch
Validate before calling
// track session state to avoid overlapping StartListening calls
if (synchronizedInputSessionActive) throw new InvalidOperationException("session already active"); Type guard
bool CanStartSession(bool sessionActive) => !sessionActive;
Try / catch
try
{
provider.StartListening(type);
synchronizedInputSessionActive = true;
}
catch (InvalidOperationException)
{
provider.CancelListening(); // end stale session, then retry
provider.StartListening(type);
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- SR.Automation_InvalidSynchronizedInputType
- SR.CannotModifyVisualChildrenDuringTreeWalk
- SR.DrawingGroup_AlreadyOpen
- SR.TextContainerChangingReentrancyInvalid
- SR.TextFormatterReentranceProhibited
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/490671364d53562a.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Automation/SynchronizedInputAdaptor.cs:46
/// <param name="inputType"> Synchronized input type</param>
void ISynchronizedInputProvider.StartListening(SynchronizedInputType inputType)
{
if (inputType != SynchronizedInputType.KeyDown &&
inputType != SynchronizedInputType.KeyUp &&
inputType != SynchronizedInputType.MouseLeftButtonDown &&
inputType != SynchronizedInputType.MouseLeftButtonUp &&
inputType != SynchronizedInputType.MouseRightButtonDown &&
inputType != SynchronizedInputType.MouseRightButtonUp)
{
throw new ArgumentException(SR.Format(SR.Automation_InvalidSynchronizedInputType, inputType));
}
UIElement e = _owner as UIElement;
if (e != null)
{
if (!e.StartListeningSynchronizedInput(inputType))
{
throw new InvalidOperationException(SR.Automation_RecursivePublicCall);
}
}
else
{
ContentElement ce = _owner as ContentElement;
if (ce != null)
{
if (!ce.StartListeningSynchronizedInput(inputType))
{
throw new InvalidOperationException(SR.Automation_RecursivePublicCall);
}
}
else
{
UIElement3D e3D = (UIElement3D)_owner;
if (!e3D.StartListeningSynchronizedInput(inputType))
{
throw new InvalidOperationException(SR.Automation_RecursivePublicCall);View on GitHub (pinned to 81131a70a4)