dotnet/aspnetcore · error · InvalidOperationException
The type ' ' does not have an associated TypeConverter that…
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.MakeTypeConverterFormatter when binding a value of type T to output (formatting T to string) and T has no TypeConverter that supports ConvertTo(typeof(string)). Blazor's bind infrastructure falls back to TypeConverter for types without a dedicated formatter; without one, formatting fails at bind time.
Solutions
- Add a TypeConverterAttribute on the type pointing to a TypeConverter subclass that implements ConvertTo for string.
- Or bind to a primitive/string property and convert to/from the custom type manually in get/set accessors.
- If the type is a record with a single value, expose the underlying primitive for binding.
Example fix
// before: custom type with no converter, bound in markup
public record CustomerId(Guid Value);
<InputText @bind-Value="customerId" />
// after: register a TypeConverter
[TypeConverter(typeof(CustomerIdConverter))]
public record CustomerId(Guid Value);
public class CustomerIdConverter : TypeConverter
{
public override bool CanConvertTo(ITypeDescriptorContext? c, Type? t) => t == typeof(string);
public override object? ConvertTo(ITypeDescriptorContext? c, CultureInfo? ci, object? v, Type t)
=> v is CustomerId id ? id.Value.ToString() : null;
public override bool CanConvertFrom(ITypeDescriptorContext? c, Type? s) => s == typeof(string);
public override object? ConvertFrom(ITypeDescriptorContext? c, CultureInfo? ci, object v)
=> new CustomerId(Guid.Parse((string)v));
} Defensive patterns
Strategy: type-guard
Validate before calling
var converter = TypeDescriptor.GetConverter(typeof(T));
if (converter == null || !converter.CanConvertTo(typeof(string))) { /* register a TypeConverter or bind a primitive */ } Type guard
static bool CanFormat<T>() { var c = TypeDescriptor.GetConverter(typeof(T)); return c != null && c.CanConvertTo(typeof(string)); } Prevention
- Prefer binding primitives/enums; wrap custom types in a converter when needed.
- Add a TypeConverter unit test for any custom bound type.
- Keep a checklist: any new bound custom type needs a registered TypeConverter.
When it happens
Trigger: Using @bind on a property whose type T has no built-in Blazor formatter and no [TypeConverter] registered that converts to string — typically a custom value type or POCO used directly in an input binding.
Common situations: Binding a custom struct/class to an <InputText> or <input>; binding a strongly-typed id (e.g. CustomerId) without a converter; binding enums is fine but custom types are not.
Related errors
- The type ' ' does not have an associated TypeConverter that…
- ' ' is flagged with SingleDelivery, but the selected…
- Authorization requires a cascading parameter of type Task
- Do not specify both 'Authorized' and 'ChildContent'.
- The authorization data specifies an authentication scheme…
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/1cc91aa6d428df9a.
Report an issue: GitHub.
Appendix: 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 3600ca084e)