dotnet/wpf · error · ArgumentException

SR.AtLeastOnePropertyMustBeSpecified

Error message

SR.AtLeastOnePropertyMustBeSpecified

What it means

Automation.AddAutomationPropertyChangedEventHandler requires a non-empty properties array since there is nothing to listen to otherwise. Passing an empty AutomationProperty[] throws ArgumentException with SR.AtLeastOnePropertyMustBeSpecified. Null arguments are separately rejected by ArgumentNullException.ThrowIfNull.

Solutions

  1. Ensure at least one AutomationProperty is in the array before calling (e.g. AutomationElement.NameProperty, IsEnabledProperty)
  2. Add a guard in your code that skips registration (or logs) when the property list is empty
  3. Validate that the dynamic property-selection logic actually yields properties

Example fix

// before
var props = selected.Select(p => p.Property).ToArray();
Automation.AddAutomationPropertyChangedEventHandler(el, handler, TreeScope.Element, props);
// after
var props = selected.Select(p => p.Property).ToArray();
if (props.Length > 0)
{
    Automation.AddAutomationPropertyChangedEventHandler(el, handler, TreeScope.Element, props);
}
Defensive patterns

Strategy: validation

Validate before calling

if (properties == null || properties.Length == 0)
    throw new InvalidOperationException("At least one AutomationProperty is required");

Try / catch

try { Automation.AddAutomationPropertyChangedEventHandler(el, handler, scope, props); }
catch (ArgumentException) { log.Warn("No properties selected; skipping registration"); }

Prevention

When it happens

Trigger: Calling Automation.AddAutomationPropertyChangedEventHandler(element, handler, scope, new AutomationProperty[0]) or an array initialized without any properties.

Common situations: Building the properties array dynamically (filtering a list) and passing the empty result; copying sample code with a placeholder empty array; configuration selecting zero properties.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/d25e4dd9c51eeb73. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClient/System/Windows/Automation/Automation.cs:222

        /// Called by a client to add a listener for property changed events.
        /// </summary>
        /// <param name="element">Element on which to listen for property changed events.</param>
        /// <param name="scope">Specifies whether to listen to property changes events on the specified element, and/or its ancestors and children.</param>
        /// <param name="eventHandler">Callback object to call when a specified property change occurs.</param>
        /// <param name="properties">Params array of properties to listen for changes in.</param>
        public static void AddAutomationPropertyChangedEventHandler(
            AutomationElement element,            // reference element for listening to the event
            TreeScope scope,                   // scope to listen to
            AutomationPropertyChangedEventHandler eventHandler,    // callback object
            params AutomationProperty [] properties           // listen for changes to these properties
            )
        {
            ArgumentNullException.ThrowIfNull(element);
            ArgumentNullException.ThrowIfNull(eventHandler);
            ArgumentNullException.ThrowIfNull(properties);
            if (properties.Length == 0)
            {
                throw new ArgumentException( SR.AtLeastOnePropertyMustBeSpecified );
            }

            // Check that no properties are interpreted properties
            // If more interpreted properties are identified add a mapping of
            // on interpreted properties to the real property that raises events.
            foreach (AutomationProperty property in properties)
            {
                ArgumentNullException.ThrowIfNull(property, nameof(properties));
            }

            // Add a client-side listener for for this event request
            EventListener l = new EventListener(AutomationElement.AutomationPropertyChangedEvent, scope, properties, CacheRequest.CurrentUiaCacheRequest);
            ClientEventManager.AddListener(element, eventHandler, l);
        }

        /// <summary>
        /// Called by a client to remove a listener for property changed events.
        /// </summary>

View on GitHub (pinned to 81131a70a4)