{"record":{"id":"cd21203cb945d1c5","repo":"dotnet/aspnetcore","slug":"the-type-0-does-not-have-an-associated-typecon-cd2120","errorCode":null,"errorMessage":"The type '{0}' does not have an associated TypeConverter that supports conversion from a string. Apply 'TypeConverterAttribute' to the type to register a converter.","messagePattern":"The type '(.+?)' does not have an associated TypeConverter that supports conversion from a string\\. Apply 'TypeConverterAttribute' to the type to register a converter\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Components/Components/src/BindConverter.cs","lineNumber":2063,"sourceCode":"                    if (!elementParser(initialArray.GetValue(i), culture, out convertedArray[i]!))\n                    {\n                        value = default;\n                        return false;\n                    }\n                }\n\n                value = convertedArray;\n                return true;\n            }\n        }\n\n        [UnconditionalSuppressMessage(\"Trimming\", \"IL2026\", Justification = \"We expect unknown underlying types are configured by application code to be retained.\")]\n        private static BindParser<T> MakeTypeConverterConverter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()\n        {\n            var typeConverter = TypeDescriptor.GetConverter(typeof(T));\n            if (typeConverter == null || !typeConverter.CanConvertFrom(typeof(string)))\n            {\n                throw new InvalidOperationException(\n                    $\"The type '{typeof(T).FullName}' does not have an associated {typeof(TypeConverter).Name} that supports \" +\n                    $\"conversion from a string. \" +\n                    $\"Apply '{typeof(TypeConverterAttribute).Name}' to the type to register a converter.\");\n            }\n\n            return ConvertWithTypeConverter;\n\n            bool ConvertWithTypeConverter(object? obj, CultureInfo? culture, out T value)\n            {\n                // We intentionally close-over the TypeConverter to cache it. The TypeDescriptor infrastructure is slow.\n                if (obj == null)\n                {\n                    value = default!;\n                    return true;\n                }\n                var converted = typeConverter.ConvertFrom(context: null, culture ?? CultureInfo.CurrentCulture, obj);\n                if (converted == null)\n                {","sourceCodeStart":2045,"sourceCodeEnd":2081,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/Components/Components/src/BindConverter.cs#L2045-L2081","documentation":"Thrown by BindConverter's ParserDelegateCache.MakeTypeConverterConverter when a type used in @bind has no TypeConverter capable of converting from a string. When the user edits an input, Blazor parses the DOM string back to the bound property's type; for non-primitive types it relies on TypeDescriptor.GetConverter, and if the converter cannot convert from string this InvalidOperationException is thrown. Apply [TypeConverter] with a converter supporting ConvertFrom(typeof(string)).","triggerScenarios":"Binding @bind to a property of a custom type without a registered TypeConverter that supports parsing strings, and the type is not among the built-in set (string, numeric, bool, DateTime, Guid, enums, arrays). The parser lookup happens at BindConverter.cs:2058-2089.","commonSituations":"Custom value type bound to an <input @bind=...>; binding to a record/struct used in forms; using a domain type that lacks a string round-trip converter.","solutions":["Create a TypeConverter subclass overriding CanConvertFrom(typeof(string)) and ConvertFrom.","Apply [TypeConverter(typeof(YourConverter))] to your custom type.","Alternatively, bind a string property and parse manually, or use a built-in type."],"exampleFix":"// before — binding a custom type throws on parse\npublic struct Money { public decimal Amount; public string Currency; }\n\n// after\n[TypeConverter(typeof(MoneyConverter))]\npublic struct Money { public decimal Amount; public string Currency; }\n\npublic class MoneyConverter : TypeConverter\n{\n    public override bool CanConvertFrom(ITypeDescriptorContext c, Type t)\n        => t == typeof(string) || base.CanConvertFrom(c, t);\n    public override object ConvertFrom(ITypeDescriptorContext c, CultureInfo ci, object v)\n        => v is string s ? new Money { Amount = decimal.Parse(s, ci) } : base.ConvertFrom(c, ci, v);\n}","handlingStrategy":"type-guard","validationCode":"var converter = TypeDescriptor.GetConverter(typeof(T));\nif (converter is null || !converter.CanConvertFrom(typeof(string)))\n    throw new InvalidOperationException($\"{typeof(T)} has no string-parsing TypeConverter.\");","typeGuard":"static bool CanParseFromString<T>()\n{\n    var converter = TypeDescriptor.GetConverter(typeof(T));\n    return converter is not null && converter.CanConvertFrom(typeof(string));\n}","tryCatchPattern":null,"preventionTips":["Implement both CanConvertFrom/ConvertFrom and CanConvertTo/ConvertTo for round-trippable custom types.","Test TypeConverter parsing with edge-case strings (empty, culture-specific formats)."],"tags":["blazor","binding","typeconverter","data-binding"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}