dotnet/wpf · error · InvalidOperationException

Property data must be a non-reference variant compatible…

Error message

Property data must be a non-reference variant compatible type.

What it means

When cloning (copying) an ExtendedProperty, Clone validates that the stored value is of a type it can deep-copy (string, primitive types, arrays of them, etc.). If the value's runtime type is not a non-reference, variant-compatible type the copy falls through to `throw new InvalidOperationException(SR.InvalidDataTypeForExtendedProperty)` — 'Property data must be a non-reference variant compatible type.'

Solutions

  1. Store only serializable, variant-compatible values: strings, primitives (int, double, bool, DateTime, etc.) and arrays of these.
  2. Convert custom objects to a supported representation (e.g. byte[] or string, such as XML/JSON) before adding as an extended property.
  3. Wrap the clone operation in try/catch for InvalidOperationException and fall back to re-attaching properties manually.
  4. Validate value types when adding property data so invalid data never enters the collection.

Example fix

// before
stroke.AddPropertyData(myCustomId, new MyMetadata { X = 1 }); // clone later throws
// after
stroke.AddPropertyData(myCustomId, Encoding.UTF8.GetBytes(JsonSerializer.Serialize(metadata)));
Defensive patterns

Strategy: validation

Validate before calling

static bool IsCloneablePropertyValue(object v) =>
    v == null || v is string || v is byte[] ||
    v is int || v is long || v is short || v is byte ||
    v is double || v is float || v is bool || v is char ||
    v is DateTime || v is decimal || v is Guid;

Type guard

static bool IsReferenceTypeValue<T>(object v) => v is T && !(v is string || v is byte[]);

Try / catch

try { var clone = original.Clone(); }
catch (InvalidOperationException) { /* re-attach property data manually */ }

Prevention

When it happens

Trigger: Storing a custom reference type (e.g. a class instance, List<T>, or arbitrary object) as an ExtendedProperty value and then cloning the owning object — e.g. cloning a Stroke or ContextNode that carries the property, or round-tripping through ink serialization APIs that clone properties.

Common situations: Attaching rich business objects to ink strokes via AddPropertyData; data persisted by another app version with an unexpected value type; corrupted or hand-edited ISF payloads whose property data doesn't match the declared type.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/ExtendedProperty.cs:204

            }
            else if (type.IsArray)
            {
                Type elementType = type.GetElementType();
                if (elementType.IsValueType && type.GetArrayRank() == 1)
                {
                    //
                    // copy the array memebers, which we know are copy
                    // on assignment value types
                    //
                    Array newArray = Array.CreateInstance(elementType, ((Array)_value).Length);
                    Array.Copy((Array)_value, newArray, ((Array)_value).Length);
                    return new ExtendedProperty(guid, newArray);
                }
            }
            //
            // we didn't find a type we expect, throw
            //
            throw new InvalidOperationException(SR.InvalidDataTypeForExtendedProperty);
        }


        private Guid _id;                // id of attribute
        private object _value;             // data in attribute
    }
}

View on GitHub (pinned to 81131a70a4)