tui-cs/Terminal.Gui · error · InvalidOperationException

T must be a numeric type that supports addition and subtract

Error message

T must be a numeric type that supports addition and subtraction.

What it means

Thrown by the NumericUpDown<T> constructor when T is not 'object' and NumericHelper.SupportsType(type) returns false — i.e. T is a type without addition/subtraction operators that the helper recognises. NumericUpDown needs to add/subtract the increment, so unsupported generic type arguments are rejected at construction rather than failing later on every keystroke.

Source

Thrown at Terminal.Gui/Views/NumericUpDown.cs:66

    private readonly ScrollButton _up;

    private View _number;
    private TextField? _editor;
    private bool _updatingText;
    private bool _editingFromUser;
    private bool _canEdit;

    /// <summary>
    ///     Initializes a new instance of the <see cref="NumericUpDown{T}"/> class.
    /// </summary>
    /// <exception cref="InvalidOperationException"></exception>
    public NumericUpDown ()
    {
        Type type = typeof (T);

        if (!(type == typeof (object) || NumericHelper.SupportsType (type)))
        {
            throw new InvalidOperationException ("T must be a numeric type that supports addition and subtraction.");
        }

        CanFocus = true;

        Width = Dim.Auto (DimAutoStyle.Content);
        Height = Dim.Auto (DimAutoStyle.Content);

        _down = new ScrollButton
        {
            Orientation = Orientation.Vertical,
            Direction = NavigationDirection.Forward
        };

        _number = CreateNumberView ();

        _up = new ScrollButton
        {
            X = Pos.Right (_number),

View on GitHub (pinned to 2e47b11478)

Solutions

  1. Use a supported numeric type: int, long, decimal, double, float, etc. — check NumericHelper.SupportsType for the exact list.
  2. For enums use OptionSelectorTEnum; for flags use FlagSelectorTEnum.
  3. If a custom numeric struct is required, ensure it exposes matching +/- operators and register/support it via the helper's accepted set, or wrap a supported primitive.

Example fix

// before
var nud = new NumericUpDown<MyEnum>(); // throws 168

// after
var nud = new NumericUpDown<int>();
// and for enums prefer:
var sel = new OptionSelectorTEnum<MyEnum>();
Defensive patterns

Strategy: type-guard

Validate before calling

Type t = typeof(T);
if (!(t == typeof(object) || NumericHelper.SupportsType(t)))
{
    // pick a supported numeric type, or use OptionSelector for enums
}

Type guard

static bool SupportsNumericUpDown<T>() =>
    typeof(T) == typeof(object) || NumericHelper.SupportsType(typeof(T));

Prevention

When it happens

Trigger: Constructing NumericUpDown<SomeEnum>, NumericUpDown<string>, NumericUpDown<CustomStruct> (no matching operators), or NumericUpDown<Guid>. Supported types are the numeric primitives handled by NumericHelper.

Common situations: Trying to use NumericUpDown for an enum (use OptionSelector/FlagSelector instead); wrapping a domain value type that lacks operator overloads; copy-pasting NumericUpDown<double> into a custom value-object generic.

Related errors


AI-assisted analysis of tui-cs/Terminal.Gui@2e47b11478 (2026-08-13). Data as JSON: /api/errors/33eb8ce1385a848e. Report an issue: GitHub.