dotnet/wpf · error
SR.Format(SR.UnserializableKeyValue…
Error message
SR.Format(SR.UnserializableKeyValue, property.Value.GetType().FullName)
What it means
MarkupWriter.WriteItem throws this InvalidOperationException (SR.UnserializableKeyValue with the property value's full type name) when a MarkupObject for a keyed item (e.g. an entry in a dictionary being serialized) exposes its key as an IsKey property. XAML serialization of keys is not implemented by this writer (the <x:Key> format was never added), so any keyed item is unserializable and the exception reports the key value's type.
Solutions
- Avoid serializing keyed dictionaries with XamlWriter.Save; write a custom serializer that emits entries explicitly.
- Flatten the dictionary into a list of key/value wrapper objects (non-keyed) before saving.
- Register a TypeConverter/ValueSerializer for the key type so items are expressed without an IsKey property.
Example fix
// before
var dict = new Dictionary<string, MyData>();
XamlWriter.Save(dict); // InvalidOperationException: UnserializableKeyValue
// after
var list = dict.Select(kv => new Entry { Key = kv.Key, Value = kv.Value }).ToList();
XamlWriter.Save(list); // public non-generic wrapper entries serialize fine Defensive patterns
Strategy: try-catch
Validate before calling
bool HasKeyedItems(object o) =>
MarkupWriter.GetMarkupObjectFor(o).Properties.Any(p => p.IsKey); Try / catch
try { XamlWriter.Save(obj, stream); }
catch (InvalidOperationException ex) when (ex.Message.Contains("key"))
{
// fall back to serializing entries as key/value wrapper objects
} Prevention
- Don't use XamlWriter.Save on dictionaries or keyed collections.
- Convert dictionaries to explicit entry wrapper lists before saving.
- Test round-trips of any collection types you intend to persist as XAML.
When it happens
Trigger: Calling XamlWriter.Save / MarkupWriter.WriteItem on a dictionary or keyed collection whose MarkupObject items expose IsKey properties - e.g. serializing a ResourceDictionary-like structure with entries the writer cannot emit.
Common situations: Serializing dictionaries of custom key types; saving resource dictionaries containing non-serializable entries; automating XAML round-trip of collections.
Related errors
- ArgumentException: path
- ArgumentException: relativeTo
- ArgumentNullException(nameof(writer))
- ArgumentNullException: path
- ArgumentNullException: relativeTo
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/81193dce69340df8.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Primitives/MarkupWriter.cs:693
bool propertyTagWritten = false;
bool explicitTagWritten = false;
foreach (MarkupObject subItem in property.Items)
{
if (!propertyTagWritten)
{
propertyTagWritten = true;
// uri is made addressable above so it is not necessary here
if (property.IsAttached || property.PropertyDescriptor == null)
{
Debug.Assert(!property.IsValueAsString, "Problem with MarkupObject implementation: String values cannnot be composite");
if (property.IsKey)
{
// When the reader supports <x:Key> ... </x:Key> format do the following:
// _writer.WriteStartElement("Key", NamespaceCache.XamlNamespace);
// The writer generates an exception for now:
throw new InvalidOperationException(SR.Format(SR.UnserializableKeyValue, property.Value.GetType().FullName));
}
else
{
string dpUri = scope.MakeAddressable(property.DependencyProperty.OwnerType);
WritePropertyStart(scope.GetPrefixOf(dpUri),
$"{property.DependencyProperty.OwnerType.Name}.{property.DependencyProperty.Name}", dpUri);
}
}
else
{
WritePropertyStart(prefix, $"{item.ObjectType.Name}.{property.PropertyDescriptor.Name}", uri);
writtenAttributes[property.Name] = property.Name;
}
explicitTagWritten = NeedToWriteExplicitTag(property, subItem);
if (explicitTagWritten)View on GitHub (pinned to 81131a70a4)