{"record":{"id":"b4b2930f1cac1ba1","repo":"unoplatform/uno","slug":"value-type-is-0-but-it-must-be-either-string-o","errorCode":null,"errorMessage":"Value type is '{0}' but it must be either string or any type that is convertible to string indicated by TypeConverterAttribute.","messagePattern":"Value type is '(.+?)' but it must be either string or any type that is convertible to string indicated by TypeConverterAttribute\\.","errorType":"exception","errorClass":"XamlXmlWriterException","httpStatus":null,"severity":"error","filePath":"src/SourceGenerators/System.Xaml/System.Xaml/XamlWriterInternalBase.cs","lineNumber":252,"sourceCode":"\n\t\tprotected abstract void OnWriteValue (object value);\n\n\t\tprotected abstract void OnWriteNamespace (NamespaceDeclaration nd);\n\t\t\n\t\tprotected string GetValueString (XamlMember xm, object value)\n\t\t{\n\t\t\t// change XamlXmlReader too if we change here.\n\t\t\tif ((value as string) == String.Empty) // FIXME: there could be some escape syntax.\n\t\t\t\treturn \"\\\"\\\"\";\n\t\t\tif (value is string)\n\t\t\t\treturn (string) value;\n\n\t\t\tvar xt = value == null ? XamlLanguage.Null : sctx.GetXamlType (value.GetType ());\n\t\t\tvar vs = xm.ValueSerializer ?? xt.ValueSerializer;\n\t\t\tif (vs != null)\n\t\t\t\treturn vs.ConverterInstance.ConvertToString (value, service_provider);\n\t\t\telse\n\t\t\t\tthrow new XamlXmlWriterException (String.Format (CultureInfo.InvariantCulture, \"Value type is '{0}' but it must be either string or any type that is convertible to string indicated by TypeConverterAttribute.\", value != null ? value.GetType () : null));\n\t\t}\n\t}\n}\n","sourceCodeStart":234,"sourceCodeEnd":256,"githubUrl":"https://github.com/unoplatform/uno/blob/04183404888ea21b4e5bfa3493e8d5f15e972c3a/src/SourceGenerators/System.Xaml/System.Xaml/XamlWriterInternalBase.cs#L234-L256","documentation":"The internal value-to-string converter in XamlWriterInternalBase throws XamlXmlWriterException when it must serialize a value to text but the value is neither a string nor a type with a ValueSerializer (via the member's ValueSerializer or the type's ValueSerializer). The converter checks for string/empty-string fast paths, then asks the XamlType for a ValueSerializer; if none exists it cannot emit a textual representation and fails.","triggerScenarios":"Saving an object graph where a property holds a complex type with no associated TypeConverter/ValueSerializer — e.g. a custom class assigned to a content property that the writer must render as text but cannot convert.","commonSituations":"Serializing domain objects that lack [TypeConverter] or ValueSerializer attributes; persisting object graphs that include non-serializable nested types in text positions; round-tripping XAML where a value type changed to a non-convertible type.","solutions":["Add a TypeConverter (and corresponding ValueSerializer) to the value's type so the writer can convert it to/from string.","Restructure the object graph so the property holds a string or a type that already has a ValueSerializer (e.g. primitives, DateTime with the XAML serializer).","If the value is genuinely complex, emit it as a nested object rather than a text value.","Use a custom XamlXmlWriter subclass overriding value handling if you need bespoke serialization."],"exampleFix":"// before\npublic class Color { public int R,G,B; } // no converter\n// obj.MyColor = new Color {...};  -> save fails\n\n// after\n[TypeConverter(typeof(ColorConverter))]\npublic class Color { public int R,G,B; }\npublic class ColorConverter : TypeConverter {\n    public override bool CanConvertTo(ITypeDescriptorContext c, Type t) => t == typeof(string);\n    public override object ConvertTo(ITypeDescriptorContext c, CultureInfo ci, object v, Type t) => /* format */;\n}","handlingStrategy":"validation","validationCode":"var xt = sctx.GetXamlType(value.GetType());\nif (!(value is string) && xt.ValueSerializer == null && member?.ValueSerializer == null)\n    throw new InvalidOperationException($\"Cannot serialize {value.GetType()} as text; add a ValueSerializer/TypeConverter.\");","typeGuard":"static bool IsSerializableAsText(object? v, XamlMember? m, XamlSchemaContext sctx) {\n    if (v is string || v is null) return true;\n    var xt = sctx.GetXamlType(v.GetType());\n    return (m?.ValueSerializer ?? xt.ValueSerializer) != null;\n}","tryCatchPattern":"try { XamlServices.Save(writer, instance); }\ncatch (XamlXmlWriterException ex) when (ex.Message.Contains(\"convertible to string\")) {\n    // identify the offending value type in the message, then attach a TypeConverter\n}","preventionTips":["Attach [TypeConverter] / ValueSerializer to custom value types you intend to serialize as XAML text.","Restrict serialized object graphs to types known to have ValueSerializers (primitives, enums, DateTime, etc.).","Add a round-trip unit test (Save then Load) for each type you persist as XAML."],"tags":["xaml","serialization","type-converter","value-serializer","xamlwriter"],"backgroundTag":null,"analyzedSha":"04183404888ea21b4e5bfa3493e8d5f15e972c3a","analyzedAt":"2026-08-13T21:08:11.651Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}