spectreconsole/spectre.console · error · InvalidOperationException

Could not convert input to a string

Error message

Could not convert input to a string

What it means

Thrown by TypeConverterHelper.ConvertToString<T>(T input) when the TypeConverter for type T returns null from ConvertToInvariantString. This is an internal helper used by Spectre.Console to stringify choice values in prompts (e.g., TextPrompt<T> with choices). The built-in TypeDescriptor system should normally return a non-null string for most types, but custom types with misconfigured TypeConverters, or exotic types without a registered converter, can return null.

Source

Thrown at src/Spectre.Console/Internal/TypeConverterHelper.cs:15

namespace Spectre.Console;

internal static class TypeConverterHelper
{
    internal const DynamicallyAccessedMemberTypes ConverterAnnotation = DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields;

    internal static bool IsGetConverterSupported =>
        !AppContext.TryGetSwitch("Spectre.Console.TypeConverterHelper.IsGetConverterSupported ", out var enabled) || enabled;

    public static string ConvertToString<T>(T input)
    {
        var result = GetTypeConverter<T>().ConvertToInvariantString(input);
        if (result == null)
        {
            throw new InvalidOperationException("Could not convert input to a string");
        }

        return result;
    }

    public static bool TryConvertFromString<T>(string input, [MaybeNull] out T? result)
    {
        try
        {
            result = (T?)GetTypeConverter<T>().ConvertFromInvariantString(input);
            return true;
        }
        catch
        {
            result = default;
            return false;
        }
    }

View on GitHub (pinned to 0acc92fada)

Solutions

  1. Provide an explicit converter or ToString override on your custom type so ConvertToInvariantString never returns null.
  2. Decorate your type with [TypeConverter(typeof(MyConverter))] that returns a non-null string.
  3. For prompt choices, use simpler types (string, int, enum) that have reliable built-in converters.
  4. If the type legitimately cannot stringify, provide a custom display via the prompt's converter parameter instead of relying on TypeConverterHelper.

Example fix

// before
public record MyId(Guid Value);
var choice = AnsiConsole.Prompt(
    new SelectionPrompt<MyId>().AddChoices(ids));

// after
[TypeConverter(typeof(MyIdConverter))]
public record MyId(Guid Value);

public class MyIdConverter : TypeConverter
{
    public override object? ConvertTo(ITypeDescriptorContext? ctx, CultureInfo? c, object value, Type dest)
        => value is MyId id ? id.Value.ToString() : null;
}
Defensive patterns

Strategy: validation

Validate before calling

// Test string conversion before using as prompt choice
var testString = TypeDescriptor.GetConverter(typeof(T))
    ?.ConvertToInvariantString(sampleValue);
if (testString is null)
{
    throw new InvalidOperationException(
        $"Type {typeof(T).Name} cannot be converted to string for prompt display.");
}

Type guard

static bool HasStringRepresentation<T>(T sample)
{
    try
    {
        var converter = TypeDescriptor.GetConverter(typeof(T));
        return converter?.ConvertToInvariantString(sample) is not null;
    }
    catch
    {
        return false;
    }
}

Try / catch

try
{
    var prompt = new SelectionPrompt<T>().AddChoices(items);
    return AnsiConsole.Prompt(prompt);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("convert input to a string"))
{
    // Fallback: provide a custom converter to the prompt
    var prompt = new SelectionPrompt<T>()
        .Converter(myConverter)
        .AddChoices(items);
    return AnsiConsole.Prompt(prompt);
}

Prevention

When it happens

Trigger: Using a SelectionPrompt or TextPrompt with a generic type T whose TypeDescriptor.GetConverter / custom TypeConverterAttribute returns null from ConvertToInvariantString. Also possible if T is a type that has no standard string representation and the fallback TypeConverter yields null.

Common situations: Custom enum or record type used as a prompt choice without a working TypeConverter; third-party types whose TypeConverterAttribute points to a converter that returns null; edge cases with nullable value types or interfaces used as prompt generics; trimming/AOT scenarios where reflection-based converter discovery is suppressed.

Related errors


AI-assisted analysis of spectreconsole/spectre.console@0acc92fada (2026-08-13). Data as JSON: /api/errors/b903dce4d4f1abc0. Report an issue: GitHub.