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
- 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;
- When filtering, reset SelectedItem to null (or 0) before swapping the Source.
- 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
- Reset SelectedItem when filtering changes Source.Count.
- Use Source.Count - 1 for 'select last', never Source.Count.
- Clamp externally-supplied indices against the live Source.
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
- value
- FocusedItem index is out of range
- Must be non-negative
- The source stream must be seekable (CanSeek property)
- Zoom level must be a finite number.
AI-assisted analysis of tui-cs/Terminal.Gui@2e47b11478 (2026-08-13).
Data as JSON: /api/errors/08ecae885a2515fe.
Report an issue: GitHub.