tui-cs/Terminal.Gui · error · InvalidOperationException

Only a single Grapheme cluster is allowed per Cell.

Error message

Only a single Grapheme cluster is allowed per Cell.

What it means

Thrown by the Cell.Grapheme setter when the assigned string contains more than one grapheme cluster (as counted by GraphemeHelper.GetGraphemeCount). A Cell models exactly one screen column and therefore holds exactly one user-perceived character (grapheme); assigning a multi-grapheme string like "ab" or "e\u0301e" violates that invariant.

Source

Thrown at Terminal.Gui/Drawing/Cell.cs:32

    ///     Gets or sets a value indicating whether this <see cref="T:Terminal.Gui.Drawing.Cell"/> has been modified since the
    ///     last time it was drawn.
    /// </summary>
    public bool IsDirty { get; set; } = IsDirty;

    private string _grapheme = Grapheme;

    /// <summary>
    ///     The single grapheme cluster to display from this cell. If <see cref="Grapheme"/> is <see langword="null"/> or
    ///     <see cref="string.Empty"/>, then <see cref="Cell"/> is ignored.
    /// </summary>
    public string Grapheme
    {
        readonly get => _grapheme;
        set
        {
            if (GraphemeHelper.GetGraphemeCount (value) > 1)
            {
                throw new InvalidOperationException ($"Only a single {nameof (Grapheme)} cluster is allowed per Cell.");
            }

            if (!string.IsNullOrEmpty (value) && value.Length == 1 && char.IsSurrogate (value [0]))
            {
                throw new ArgumentException ($"Only valid Unicode scalar values are allowed in a single {nameof (Grapheme)} cluster.");
            }

            try
            {
                _grapheme = !string.IsNullOrEmpty (value) && !value.IsNormalized (NormalizationForm.FormC)
                                ? value.Normalize (NormalizationForm.FormC)
                                : value;
            }
            catch (ArgumentException)
            {
                // leave text unnormalized
                _grapheme = value;
            }

View on GitHub (pinned to 2e47b11478)

Solutions

  1. Use Cell.ToCellList(str, attribute) (or Cell.StringToCells) to split any string into one Cell per grapheme cluster — it uses GraphemeHelper.GetGraphemes internally.
  2. If you must assign manually, verify GraphemeHelper.GetGraphemeCount(value) <= 1 first.
  3. For combining sequences (base + combining marks), note those count as a SINGLE grapheme and are allowed; the error is only for 2+ clusters.

Example fix

// before
Cell cell = new () { Grapheme = "ab" }; // throws

// after
List<Cell> cells = Cell.ToCellList ("ab"); // [Cell{a}, Cell{b}]
Defensive patterns

Strategy: validation

Validate before calling

// Confirm at most one grapheme cluster before assigning
if (GraphemeHelper.GetGraphemeCount (value) > 1)
    throw new ArgumentException ("Use Cell.ToCellList to split multi-grapheme strings.");
cell.Grapheme = value;

Type guard

static bool IsValidCellGrapheme (string s) => GraphemeHelper.GetGraphemeCount (s) <= 1;

Prevention

When it happens

Trigger: Directly assigning cell.Grapheme = "ab", or constructing new Cell { Grapheme = multiClusterString }, or a code path that pushes an unsplit string into a single Cell instead of a List<Cell>.

Common situations: Treating Cell like a general string holder; receiving user input and storing it in one cell instead of segmenting it; an off-by-one when slicing a string into cells.

Related errors


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