dotnet/machinelearning · error · NotSupportedException

Strings.ImmutableColumn

Error message

Strings.ImmutableColumn

What it means

ArrowStringDataFrameColumn is immutable: the protected SetValue override always throws NotSupportedException(Strings.ImmutableColumn). Any API that mutates a single value by row index (the base-class indexer setter, FillWith value assignment paths) hits this throw. The column only supports append-style construction and reads.

Source

Thrown at src/Microsoft.Data.Analysis/DataFrameColumns/ArrowStringDataFrameColumn.cs:278

            {
                fixed (byte* data = &MemoryMarshal.GetReference(bytes))
                    return Encoding.UTF8.GetString(data, bytes.Length);
            }
        }

        /// <inheritdoc/>
        protected override IReadOnlyList<object> GetValues(long startIndex, int length)
        {
            var ret = new List<object>();
            while (ret.Count < length)
            {
                ret.Add(GetValueImplementation(startIndex++));
            }
            return ret;
        }

        /// <inheritdoc/>
        protected override void SetValue(long rowIndex, object value) => throw new NotSupportedException(Strings.ImmutableColumn);


        /// <summary>
        /// Indexer to get values. This is an immutable column
        /// </summary>
        /// <param name="rowIndex">Zero based row index</param>
        /// <returns>The value stored at this <paramref name="rowIndex"/></returns>
        public new string this[long rowIndex]
        {
            get => GetValueImplementation(rowIndex);
            set => throw new NotSupportedException(Strings.ImmutableColumn);
        }

        /// <summary>
        /// Returns <paramref name="length"/> number of values starting from <paramref name="startIndex"/>.
        /// </summary>
        /// <param name="startIndex">The index of the first value to return.</param>
        /// <param name="length">The number of values to return starting from <paramref name="startIndex"/></param>

View on GitHub (pinned to 7b76e69cf9)

Solutions

  1. Do not mutate in place: build a new column with modified values and replace it in the collection.
  2. Use a regular StringDataFrameColumn (or PrimitiveDataFrameColumn) when in-place edits are required.
  3. Route writes through Append (on a fresh column) rather than SetValue-based APIs.
  4. Wrap mutation logic in a check: if (col is ArrowStringDataFrameColumn) clone-and-replace, else mutate.

Example fix

// before
((DataFrameColumn)df.Columns["s"])[5] = "new"; // NotSupportedException

// after
var values = Enumerable.Range(0, (int)df.Columns["s"].Length)
    .Select(i => i == 5 ? "new" : df.Columns["s"][i].ToString());
df["s"] = new StringDataFrameColumn("s", values);
Defensive patterns

Strategy: type-guard

Validate before calling

if (df.Columns[name] is ArrowStringDataFrameColumn)
    throw new InvalidOperationException("Column is immutable; replace instead of mutating");

Type guard

static bool IsMutableColumn(DataFrameColumn c) => c is not ArrowStringDataFrameColumn;

Try / catch

try { baseCol[rowIndex] = value; }
catch (NotSupportedException) { /* rebuild column with updated value and reassign */ }

Prevention

When it happens

Trigger: Assigning through the base DataFrameColumn indexer ((DataFrameColumn)col)[rowIndex] = value, calling base-class APIs that call SetValue (e.g. certain Fill/apply implementations), or any mutation helper built on SetValue.

Common situations: Treating an Arrow-backed column (loaded from Arrow IPC/Feather) like a regular editable PrimitiveDataFrameColumn; generic code written against DataFrameColumn that mutates in place.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of dotnet/machinelearning@7b76e69cf9 (2026-09-11). Data as JSON: /api/errors/2c24ac52790bfaa3. Report an issue: GitHub.