dotnet/wpf · error · ArgumentException

Property data must be a non-reference variant compatible…

Error message

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

What it means

Thrown by SerializationHelper.ConvertToVarEnum (with throwOnError=true) when an ExtendedProperty value's type has no compatible non-reference VARIANT representation. ISF extended properties must be storable as a by-value VarEnum; types like objects, unknown COM references, or unsupported managed types cannot be serialized into ISF.

Solutions

  1. Store only VARIANT-compatible types in extended properties: numeric primitives, bool, string, DateTime, byte[], and safe arrays of these
  2. Convert custom objects to a byte[] or string representation before adding as an extended property
  3. Catch ArgumentException around save/serialization and remove or convert offending ExtendedProperty keys
  4. If the value type is legitimately unsupported (ConvertToVarEnum returned VT_UNKNOWN when throwOnError=false), skip persisting that property

Example fix

// before
stroke.AddPropertyData(myGuid, new MyCustomClass { X = 1 }); // throws on ISF save
// after
stroke.AddPropertyData(myGuid, BitConverter.GetBytes(myValue)); // store as byte[]
// or serialize the object to a string/byte[] yourself:
stroke.AddPropertyData(myGuid, Encoding.UTF8.GetBytes(JsonSerializer.Serialize(obj)));
Defensive patterns

Strategy: type-guard

Validate before calling

static readonly HashSet<Type> VariantCompatible = new() {
    typeof(int), typeof(uint), typeof(short), typeof(ushort), typeof(long), typeof(ulong),
    typeof(float), typeof(double), typeof(decimal), typeof(bool), typeof(string),
    typeof(DateTime), typeof(byte[])
};
static bool IsExtendedPropertyStorable(object v) =>
    v != null && (VariantCompatible.Contains(v.GetType()) ||
      (v is Array a && a.Length > 0 && VariantCompatible.Contains(a.GetType().GetElementType())));

Type guard

bool IsStorableExtendedProperty(object value) => value is int or uint or short or ushort or long or ulong or float or double or decimal or bool or string or DateTime or byte[];

Try / catch

try { scs.Save(stream); }
catch (ArgumentException ex) when (ex.Message.Contains("variant")) {
    log.Warn("Unsupported extended property type", ex);
    // remove offending ExtendedProperty and retry save
}

Prevention

When it happens

Trigger: Adding a Stroke/StrokeCollection/StylusPoint Description extended property whose value is not a primitive (e.g. a custom class, array of unsupported element type, or object) and then serializing to ISF via StrokeCollectionSerializer.Save / ExtendedPropertySerializer.EncodeAsISF.

Common situations: Developers storing arbitrary .NET objects in Stroke extended properties and later saving to ISF; passing byte[][] or nested collections; upgrading code that previously used XML persistence to ISF persistence.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/InkSerializedFormat/SerializationHelper.cs:322

                return (VarEnum.VT_ARRAY | VarEnum.VT_BOOL);
            }
            else if (typeof(String) == type)
            {
                return VarEnum.VT_BSTR;
            }
            else if (typeof(Decimal) == type)
            {
                return VarEnum.VT_DECIMAL;
            }
            else if (typeof(Decimal[]) == type)
            {
                return (VarEnum.VT_ARRAY | VarEnum.VT_DECIMAL);
            }
            else
            {
                if (throwOnError)
                {
                    throw new ArgumentException(SR.InvalidDataTypeForExtendedProperty);
                }
                else
                {
                    return VarEnum.VT_UNKNOWN;
                }
            }
        }
    }
}

View on GitHub (pinned to 81131a70a4)