AvaloniaUI/Avalonia · error · ArgumentException

The pseudoclass '{name}' may only be {operation} by the cont

Error message

The pseudoclass '{name}' may only be {operation} by the control itself.

What it means

Thrown by Classes.ThrowIfPseudoclass when an attempt is made to add or remove a pseudoclass (a class name starting with ':') through the public Classes collection. Pseudoclasses represent control visual states (e.g. ':pointerover', ':pressed') and are managed exclusively by the control itself via the protected StyledElement.PseudoClasses accessor, never by external code.

Source

Thrown at src/Avalonia.Base/Controls/Classes.cs:327

        internal void RemoveListener(IClassesChangedListener listener)
        {
            _listeners?.Remove(listener);
        }

        private void NotifyChanged()
        {
            if (_listeners is null)
                return;
            foreach (var listener in _listeners)
                listener.Changed();
        }

        private static void ThrowIfPseudoclass(string name, string operation)
        {
            if (name.StartsWith(":"))
            {
                throw new ArgumentException(
                    $"The pseudoclass '{name}' may only be {operation} by the control itself.");
            }
        }

        /// <summary>
        /// Adds a or removes a  style class to/from the collection.
        /// </summary>
        /// <param name="name">The class names.</param>
        /// <param name="value">If true adds the class, if false, removes it.</param>
        /// <remarks>
        /// Only standard classes may be added or removed via this method. To add pseudoclasses (classes
        /// beginning with a ':' character) use the protected <see cref="StyledElement.PseudoClasses"/>
        /// property.
        /// </remarks>
        public void Set(string name, bool value)
        {
            if (value)
            {

View on GitHub (pinned to 11c5427268)

Solutions

  1. If the class name should not start with ':', strip the colon before passing to Classes.Add/Remove.
  2. If you genuinely need to set a pseudoclass, call the protected PseudoClasses.Set(":name", value) from within the control (or a custom control subclass), not the public Classes API.
  3. If toggling a state from outside the control, expose a public property/styleable property on the control that internally sets PseudoClasses.

Example fix

// before
myControl.Classes.Add(":pressed");
// after — from inside the control or a subclass
PseudoClasses.Set(":pressed", true);
Defensive patterns

Strategy: validation

Validate before calling

static bool IsPseudoclass(string name) => name.StartsWith(":");
// before mutating Classes:
if (!IsPseudoclass(name))
    control.Classes.Add(name);

Try / catch

try { control.Classes.Add(name); }
catch (ArgumentException ex) when (ex.Message.Contains("pseudoclass"))
{
    // route to PseudoClasses.Set from within the control instead
}

Prevention

When it happens

Trigger: Calling control.Classes.Add(":pressed"), control.Classes.Remove(":pointerover"), or any Classes collection mutation (Add/Remove/Insert) where the name argument starts with ':'. The guard fires in 9 call sites across Classes.cs (lines 66, 90, 130, 155, 183, 209, 235, 261).

Common situations: Developer confuses style classes (e.g. "active") with pseudoclasses (":active") and tries to toggle a pseudoclass from a view model or behavior. Migrating from WPF where pseudo-classes were sometimes manipulated differently. Dynamically building class names and accidentally prepending ':'.

Related errors


AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13). Data as JSON: /api/errors/775246da0d8d3111. Report an issue: GitHub.