tui-cs/Terminal.Gui · error · InvalidOperationException
Setting Values directly is not allowed.
Error message
Setting Values directly is not allowed.
What it means
Thrown by the OptionSelectorTEnum.Values override setter unconditionally — the enum-typed selector deliberately blocks direct writes to the inherited int-based Values collection. For an enum selector, valid values come from the enum members, so allowing arbitrary int lists would break the TEnum mapping. The getter still delegates to base.
Source
Thrown at Terminal.Gui/Views/Selectors/OptionSelectorTEnum.cs:38
base.Values = Enum.GetValues<TEnum> ().Select (f => Convert.ToInt32 (f)).ToList ().AsReadOnly ();
// Set labels, which triggers CreateSubViews + UpdateChecked.
Labels = Enum.GetNames<TEnum> ();
}
/// <summary>
/// Gets or sets the value of the selected option.
/// </summary>
public new TEnum? Value
{
get => base.Value.HasValue ? (TEnum)Enum.ToObject (typeof (TEnum), base.Value.Value) : null;
set => base.Value = value.HasValue ? Convert.ToInt32 (value.Value) : null;
}
/// <summary>
/// Prevents calling the base Values property setter with arbitrary values.
/// </summary>
public override IReadOnlyList<int>? Values { get => base.Values; set => throw new InvalidOperationException ("Setting Values directly is not allowed."); }
/// <summary>
/// Raised when <see cref="Value"/> has changed. Provides the new value as <typeparamref name="TEnum"/>?.
/// </summary>
public new event EventHandler<EventArgs<TEnum?>>? ValueChanged;
/// <summary>
/// Called when <see cref="Value"/> has changed. Raises the generic <see cref="ValueChanged"/> event.
/// </summary>
protected override void OnValueChanged (int? value, int? previousValue)
{
base.OnValueChanged (value, previousValue);
TEnum? newValue = value.HasValue ? (TEnum)Enum.ToObject (typeof (TEnum), value.Value) : null;
ValueChanged?.Invoke (this, new EventArgs<TEnum?> (newValue));
}
View on GitHub (pinned to 2e47b11478)
Solutions
- Do not set Values on the enum selector — the values are derived from TEnum automatically when you set Options/Source.
- If you need a custom value set, use the non-generic OptionSelector (int-based) instead of OptionSelectorTEnum<TEnum>.
- Exclude this property from serialisers/binders (make it read-only in the binding map).
Example fix
// before
var sel = new OptionSelectorTEnum<MyEnum>();
sel.Values = new[] { 0, 1, 2 }; // throws 171
// after
var sel = new OptionSelectorTEnum<MyEnum>();
sel.Value = MyEnum.Second; // set selection via the typed Value
// and for custom value sets use the int selector:
var intSel = new OptionSelector { Values = [0,1,2] }; Defensive patterns
Strategy: type-guard
Validate before calling
// Do not assign Values on an enum selector; set Value or use the int-based OptionSelector
if (selector is OptionSelectorTEnum<_>) { /* use .Value only */ } Type guard
static bool ValuesIsReadOnly(SelectorBase s) => s is OptionSelectorTEnum<_>;
Prevention
- Never set Values on OptionSelectorTEnum — it is intentionally read-only.
- Use the non-generic OptionSelector when you need custom value sets.
- Exclude Values from serialisers/binders for enum selectors.
When it happens
Trigger: Assigning optionSelectorEnum.Values = someList; in code, or via reflection/serialisation/binder that targets the Values property. Any write attempt fails by design.
Common situations: Generic/binding code that sets Values across selector types without special-casing enums; config/deserialisation trying to populate Values directly; refactor that routed selection through the base property.
Related errors
- FocusedItem index is out of range
- Expected a valid text style value.
- {propertyName}: "{reader.GetString ()}" is not a valid Key.
- Invalid scheme name: {schemeName}
- Invalid TraceCategory value: '{value}'
AI-assisted analysis of tui-cs/Terminal.Gui@2e47b11478 (2026-08-13).
Data as JSON: /api/errors/4e749b982863c3ed.
Report an issue: GitHub.