dotnet/wpf · error · InvalidOperationException

SR.Format(SR.Freezable_CloneInvalidType, typeof(T).Name)

Error message

SR.Format(SR.Freezable_CloneInvalidType, typeof(T).Name)

What it means

CloneCommon throws InvalidOperationException(SR.Freezable_CloneInvalidType) when cloning a FreezableCollection whose element type T cannot be cloned: the item is neither Freezable nor ICloneable (or otherwise not handled by the CloneCommonType switch), so the cloned item newValue remains null. It indicates T is a type the clone machinery cannot deep-copy.

Solutions

  1. Make T a Freezable-derived type (override CloneCore/CloneCurrentValueCore) so the clone machinery can copy elements.
  2. Implement cloning support for T (Freezable) instead of a plain class.
  3. Perform a manual copy (foreach item, create and populate a new instance) rather than calling Clone.

Example fix

// before
class MyItem { public int X; }
var col = new FreezableCollection<MyItem>();
var copy = col.Clone(); // throws
// after
class MyItem : Freezable {
  public int X { get; set; }
  protected override Freezable CreateInstanceCore() => new MyItem();
  protected override void CloneCore(Freezable source) { X = ((MyItem)source).X; }
}
Defensive patterns

Strategy: validation

Validate before calling

bool cloneable = typeof(Freezable).IsAssignableFrom(typeof(T)) || typeof(ICloneable).IsAssignableFrom(typeof(T));
if (!cloneable) throw new InvalidOperationException($"{typeof(T).Name} cannot be cloned; derive it from Freezable.");

Type guard

static bool IsCloneableElement<T>() => typeof(Freezable).IsAssignableFrom(typeof(T)) || typeof(ICloneable).IsAssignableFrom(typeof(T));

Try / catch

try { var copy = collection.Clone(); }
catch (InvalidOperationException ex) { /* fall back to manual copy of elements */ }

Prevention

When it happens

Trigger: Calling Clone/CloneCore/CloneCurrentValueCore/GetAsFrozen/GetCurrentValueAsFrozen on a FreezableCollection<T> where T is not Freezable and lacks a supported clone path, e.g. FreezableCollection<SomePoco> or a custom type not deriving from Freezable.

Common situations: Declaring FreezableCollection<T> with a plain business object for convenience, then freezing/cloning the collection for animation or thread marshalling; SDK retargeting where a custom element type lost its Freezable base.

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 dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/cf80007a1865ba2a. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/FreezableCollection.cs:826

                        newValue = itemAsFreezable.Clone() as T;
                        break;
                    case CloneCommonType.CloneCurrentValue:
                        newValue = itemAsFreezable.CloneCurrentValue() as T;
                        break;
                    case CloneCommonType.GetAsFrozen:
                        newValue = itemAsFreezable.GetAsFrozen() as T;
                        break;
                    case CloneCommonType.GetCurrentValueAsFrozen:
                        newValue = itemAsFreezable.GetCurrentValueAsFrozen() as T;
                        break;
                    default:
                        Invariant.Assert(false, "Invalid CloneCommonType encountered.");
                        break;
                    }

                    if (newValue == null)
                    {
                        throw new InvalidOperationException(SR.Format(SR.Freezable_CloneInvalidType, typeof(T).Name));
                    }
                }

                OnFreezablePropertyChanged(oldValue: null, newValue);
                _collection.Add(newValue);
            }
        }

        /// <summary>
        /// Implementation of Freezable.CloneCore()
        /// </summary>
        protected override void CloneCore(Freezable source)
        {
            base.CloneCore(source);

            FreezableCollection<T> sourceFreezableCollection = (FreezableCollection<T>) source;

            CloneCommon(sourceFreezableCollection, CloneCommonType.Clone);

View on GitHub (pinned to 81131a70a4)