dotnet/aspnetcore · error · InvalidOperationException
The type '{0}' does not have an associated TypeConverter tha
Error message
The type '{0}' does not have an associated TypeConverter that supports conversion to a string. Apply 'TypeConverterAttribute' to the type to register a converter. What it means
Thrown by BindConverter's FormatterDelegateCache.MakeTypeConverterFormatter when a type used in @bind has no TypeConverter capable of converting it to a string. Blazor needs to render bound values into input elements; for non-primitive types it falls back to TypeDescriptor.GetConverter, and if that converter can't convert to string, this InvalidOperationException is thrown. The fix is to apply [TypeConverter] on the type registering a converter that supports ConvertTo(typeof(string)).
Source
Thrown at src/Components/Components/src/BindConverter.cs:1848
{
builder.Append(", \"");
builder.Append(JsonEncodedText.Encode(elementFormatter(value[i], culture)?.ToString() ?? string.Empty).Value);
builder.Append('\"');
}
builder.Append(']');
return builder.ToString();
}
}
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "We expect unknown underlying types are configured by application code to be retained.")]
private static BindFormatter<T> MakeTypeConverterFormatter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
{
var typeConverter = TypeDescriptor.GetConverter(typeof(T));
if (typeConverter == null || !typeConverter.CanConvertTo(typeof(string)))
{
throw new InvalidOperationException(
$"The type '{typeof(T).FullName}' does not have an associated {typeof(TypeConverter).Name} that supports " +
$"conversion to a string. " +
$"Apply '{typeof(TypeConverterAttribute).Name}' to the type to register a converter.");
}
return FormatWithTypeConverter;
string? FormatWithTypeConverter(T value, CultureInfo? culture)
{
// We intentionally close-over the TypeConverter to cache it. The TypeDescriptor infrastructure is slow.
return typeConverter.ConvertToString(context: null, culture ?? CultureInfo.CurrentCulture, value);
}
}
}
internal static class ParserDelegateCache
{
private static readonly ConcurrentDictionary<Type, Delegate> _cache = new ConcurrentDictionary<Type, Delegate>();View on GitHub (pinned to 294cab2f9b)
Solutions
- Create a TypeConverter subclass that overrides CanConvertTo(typeof(string)) and ConvertTo for string.
- Apply [TypeConverter(typeof(YourConverter))] to your custom type.
- Alternatively, bind a primitive/string property and convert in get/set accessors or in a separate computed property.
Example fix
// before
public struct Money
{
public decimal Amount;
public string Currency;
}
@* @bind to Money throws *@
// after
[TypeConverter(typeof(MoneyConverter))]
public struct Money { public decimal Amount; public string Currency; }
public class MoneyConverter : TypeConverter
{
public override bool CanConvertTo(ITypeDescriptorContext c, Type t)
=> t == typeof(string) || base.CanConvertTo(c, t);
public override object ConvertTo(ITypeDescriptorContext c, CultureInfo c2, object v, Type t)
=> t == typeof(string) ? ((Money)v).Amount.ToString(c2) : base.ConvertTo(c, c2, v, t);
} Defensive patterns
Strategy: type-guard
Validate before calling
var converter = TypeDescriptor.GetConverter(typeof(T));
if (converter is null || !converter.CanConvertTo(typeof(string)))
throw new InvalidOperationException($"{typeof(T)} has no string TypeConverter."); Type guard
static bool CanFormatAsString<T>()
{
var converter = TypeDescriptor.GetConverter(typeof(T));
return converter is not null && converter.CanConvertTo(typeof(string));
} Prevention
- Always apply [TypeConverter] to custom types used in @bind.
- Prefer binding to primitive/string properties and converting in code for exotic types.
When it happens
Trigger: Using @bind on an <input> element bound to a property of a custom type that has no TypeConverter registered, and is not one of the built-in supported types (string, int, bool, DateTime, Guid, enums, arrays, etc.). The formatter lookup happens at BindConverter.cs:1843-1861.
Common situations: Binding a custom struct/record/class (e.g., a Money, EmailAddress, or custom Identifier type) to an input without registering a TypeConverter; using a third-party value type that doesn't ship a converter.
Related errors
- The type '{0}' does not have an associated TypeConverter tha
- There is no file with ID ${fileId}. The file list may have c
- Invalid sequence number or identifier '${sequenceOrIdentifie
- The options parameter is required.
- The event '${eventName}' is already registered.
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/1cc91aa6d428df9a.
Report an issue: GitHub.