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 from a string. Apply 'TypeConverterAttribute' to the type to register a converter.

What it means

Thrown by BindConverter.MakeTypeConverterConverter when parsing user input back into type T (string -> T) and T has no TypeConverter supporting ConvertFrom(typeof(string)). This is the inbound counterpart of 236: Blazor needs a converter to turn the posted string into the bound property's type.

Solutions

  1. Add a TypeConverterAttribute with a converter that implements CanConvertFrom(string) and ConvertFrom.
  2. Or bind a primitive property and map to the custom type on submit.
  3. Ensure the converter handles the empty string (return default(T) or report an error) to avoid edge-case failures.

Example fix

// before: no parse path for the custom type
public struct Money { public decimal Amount; }
<InputNumber @bind-Value="model.Price" />

// after: TypeConverter implementing ConvertFrom
[TypeConverter(typeof(MoneyConverter))]
public struct Money { public decimal Amount; public Money(decimal a){Amount=a;} }

public class MoneyConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext? c, Type? s) => s == typeof(string);
    public override object? ConvertFrom(ITypeDescriptorContext? c, CultureInfo? ci, object v)
        => decimal.TryParse((string)v, NumberStyles.Currency, ci, out var d) ? new Money(d) : new Money(0m);
    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 Money m ? m.Amount.ToString("C", ci) : null;
}
Defensive patterns

Strategy: type-guard

Validate before calling

var converter = TypeDescriptor.GetConverter(typeof(T));
if (converter == null || !converter.CanConvertFrom(typeof(string))) { /* add TypeConverter or bind a primitive */ }

Type guard

static bool CanParse<T>() { var c = TypeDescriptor.GetConverter(typeof(T)); return c != null && c.CanConvertFrom(typeof(string)); }

Prevention

When it happens

Trigger: Using @bind on a property of a custom type that lacks a TypeConverter for parsing from string, so when the user submits input Blazor cannot produce a T from the entered text.

Common situations: Custom value types/POCOs bound to form inputs without a registered converter; binding a wrapper type that has a ToString but no parse path.

Related errors


AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11). Data as JSON: /api/errors/cd21203cb945d1c5. Report an issue: GitHub.

Appendix: source

Thrown at src/Components/Components/src/BindConverter.cs:2063

                    if (!elementParser(initialArray.GetValue(i), culture, out convertedArray[i]!))
                    {
                        value = default;
                        return false;
                    }
                }

                value = convertedArray;
                return true;
            }
        }

        [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "We expect unknown underlying types are configured by application code to be retained.")]
        private static BindParser<T> MakeTypeConverterConverter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
        {
            var typeConverter = TypeDescriptor.GetConverter(typeof(T));
            if (typeConverter == null || !typeConverter.CanConvertFrom(typeof(string)))
            {
                throw new InvalidOperationException(
                    $"The type '{typeof(T).FullName}' does not have an associated {typeof(TypeConverter).Name} that supports " +
                    $"conversion from a string. " +
                    $"Apply '{typeof(TypeConverterAttribute).Name}' to the type to register a converter.");
            }

            return ConvertWithTypeConverter;

            bool ConvertWithTypeConverter(object? obj, CultureInfo? culture, out T value)
            {
                // We intentionally close-over the TypeConverter to cache it. The TypeDescriptor infrastructure is slow.
                if (obj == null)
                {
                    value = default!;
                    return true;
                }
                var converted = typeConverter.ConvertFrom(context: null, culture ?? CultureInfo.CurrentCulture, obj);
                if (converted == null)
                {

View on GitHub (pinned to 3600ca084e)