PrismLibrary/Prism · error · ArgumentException

is already being observed.

Error message

{propertyExpression} is already being observed.

What it means

DelegateCommandBase.ObservesPropertyInternal throws ArgumentException when the same property expression is observed more than once on the command. This prevents duplicate subscriptions to RaiseCanExecuteChanged for the same property.

Solutions

  1. Remove the duplicate ObservesProperty call so each property is observed once.
  2. Combine into a single call site (e.g. only in the base constructor chain).
  3. Track already-observed properties if construction is dynamic.

Example fix

// before
SaveCommand = new DelegateCommand(Save, () => CanSave)
    .ObservesProperty(() => CanSave)
    .ObservesProperty(() => CanSave); // duplicate
// after
SaveCommand = new DelegateCommand(Save, () => CanSave)
    .ObservesProperty(() => CanSave);
Defensive patterns

Strategy: validation

Validate before calling

var expr = nameof(CanSave);
// ensure ObservesProperty(() => CanSave) appears only once in the fluent chain

Try / catch

try { cmd.ObservesProperty(() => CanSave); }
catch (ArgumentException ex) { logger.LogWarning(ex, "property already observed"); }

Prevention

When it happens

Trigger: Calling ObservesProperty(()=>Foo) (or using ObservesProperty in the constructor helpers) twice with an equivalent expression for the same property on the same command instance.

Common situations: Copy-pasted fluent constructor chains that include the same property twice; subclass constructors calling base with ObservesProperty and then calling ObservesProperty again for the same property.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of PrismLibrary/Prism@358118cd64 (2026-09-15). Data as JSON: /api/errors/661887cca3552883. Report an issue: GitHub.

Appendix: source

Thrown at src/Prism.Core/Commands/DelegateCommandBase.cs:100

        protected abstract void Execute(object? parameter);

        /// <summary>
        /// Handle the internal invocation of <see cref="ICommand.CanExecute(object)"/>
        /// </summary>
        /// <param name="parameter"></param>
        /// <returns><see langword="true"/> if the Command Can Execute, otherwise <see langword="false" /></returns>
        protected abstract bool CanExecute(object? parameter);

        /// <summary>
        /// Observes a property that implements INotifyPropertyChanged, and automatically calls DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.
        /// </summary>
        /// <typeparam name="T">The object type containing the property specified in the expression.</typeparam>
        /// <param name="propertyExpression">The property expression. Example: ObservesProperty(() => PropertyName).</param>
        protected internal void ObservesPropertyInternal<T>(Expression<Func<T>> propertyExpression)
        {
            if (_observedPropertiesExpressions.Contains(propertyExpression.ToString()))
            {
                throw new ArgumentException($"{propertyExpression} is already being observed.",
                    nameof(propertyExpression));
            }
            else
            {
                _observedPropertiesExpressions.Add(propertyExpression.ToString());
                PropertyObserver.Observes(propertyExpression, RaiseCanExecuteChanged);
            }
        }

        #region IsActive

        /// <summary>
        /// Gets or sets a value indicating whether the object is active.
        /// </summary>
        /// <value><see langword="true" /> if the object is active; otherwise <see langword="false" />.</value>
        public bool IsActive
        {
            get => _isActive;

View on GitHub (pinned to 358118cd64)