tui-cs/Terminal.Gui · error · ArgumentException

SelectedItem must be greater than 0 or less than the number

Error message

SelectedItem must be greater than 0 or less than the number of items.

What it means

Thrown by ListView.SelectedItem setter when value is non-null and is < 0 or >= Source.Count. ListView uses the index into the bound Source for selection, so an out-of-range index has no row to point at. The setter early-returns if Source is null (no items), so the throw only happens when there IS a source but the index falls outside it.

Source

Thrown at Terminal.Gui/Views/ListView/ListView.Selection.cs:355

    public event EventHandler<ValueChangedEventArgs<object?>>? ValueChangedUntyped;

    #endregion

    /// <summary>This is a convenience property that is an alias for <see cref="Value"/>. Get or set the index of the currently selected item.</summary>
    /// <value>The index of selected item or <see langword="null"/> if no item is selected.</value>
    public int? SelectedItem
    {
        get;
        set
        {
            if (Source is null)
            {
                return;
            }

            if (value.HasValue && (value < 0 || value >= Source.Count))
            {
                throw new ArgumentException (@"SelectedItem must be greater than 0 or less than the number of items.");
            }

            int? oldValue = field;

            if (oldValue == value)
            {
                return;
            }

            ValueChangingEventArgs<int?> changingArgs = new (oldValue, value);

            if (OnValueChanging (changingArgs) || changingArgs.Handled)
            {
                return;
            }

            ValueChanging?.Invoke (this, changingArgs);

View on GitHub (pinned to 2e47b11478)

Solutions

  1. Clamp or null the index against the current Source.Count before assigning: listView.SelectedItem = Source.Count > 0 ? Math.Clamp(idx, 0, Source.Count - 1) : null;
  2. When filtering, reset SelectedItem to null (or 0) before swapping the Source.
  3. Use Source.Count - 1 for 'select last', not Source.Count.

Example fix

// before
listView.SelectedItem = lastIndex; // lastIndex now stale after filter

// after
listView.SelectedItem = listView.Source is { Count: > 0 } src
    ? Math.Clamp(lastIndex, 0, src.Count - 1)
    : null;
Defensive patterns

Strategy: validation

Validate before calling

if (listView.Source is { Count: > 0 } src)
{
    listView.SelectedItem = Math.Clamp(idx, 0, src.Count - 1);
}
else
{
    listView.SelectedItem = null;
}

Type guard

static bool IsValidSelection(int? i, int count) => !i.HasValue || (i >= 0 && i < count);

Prevention

When it happens

Trigger: Setting SelectedItem from a previously captured index after the underlying list shrank (items removed/filtered); computing the index from a search that returned -1; off-by-one using Count instead of Count-1; setting before the Source is assigned in one path but after in another.

Common situations: Filtering/search that reduces Source.Count without resetting the selection; navigation 'select last' using list.Count (not Count-1); binding to an ObservableCollection that mutated underneath.

Related errors


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