dotnet/machinelearning · error · ArgumentNullException

selector

Error message

selector

What it means

The DataViewSchema.Builder.Add(Annotations, Func<string,bool>) overload requires a non-null selector predicate that decides which annotation columns to copy. Passing null is treated as a programming error, so the builder throws ArgumentNullException named 'selector'.

Source

Thrown at src/Microsoft.ML.DataView/DataViewSchema.cs:277

                public Builder()
                {
                    _items = new List<(string Name, DataViewType Type, Delegate Getter, Annotations Annotations)>();
                }

                /// <summary>
                /// Add some columns from <paramref name="annotations"/> into our new annotations, by applying <paramref name="selector"/>
                /// to all the names.
                /// </summary>
                /// <param name="annotations">The annotations row to take values from.</param>
                /// <param name="selector">The predicate describing which annotation columns to keep.</param>
                public void Add(Annotations annotations, Func<string, bool> selector)
                {
                    if (annotations == null)
                        return;

                    if (selector == null)
                        throw new ArgumentNullException(nameof(selector));

                    foreach (var column in annotations.Schema)
                    {
                        if (selector(column.Name))
                            _items.Add((column.Name, column.Type, annotations.GetGetterInternal(column.Index), column.Annotations));
                    }
                }

                /// <summary>
                /// Add one annotation column, strongly-typed version.
                /// </summary>
                /// <typeparam name="TValue">The type of the value.</typeparam>
                /// <param name="name">The annotation name.</param>
                /// <param name="type">The annotation type.</param>
                /// <param name="getter">The getter delegate.</param>
                /// <param name="annotations">Annotations of the input column. Note that annotations on an annotation column is somewhat rare
                /// except for certain types (for example, slot names for a vector, key values for something of key type).</param>
                public void Add<TValue>(string name, DataViewType type, ValueGetter<TValue> getter, Annotations annotations = null)

View on GitHub (pinned to 7b76e69cf9)

Solutions

  1. Pass a predicate that accepts everything if you want all annotations: name => true
  2. Only call the overload when you genuinely have a filter; otherwise use the non-selective copy path
  3. Assert or default the selector before calling: selector ?? (_ => true)

Example fix

// before
builder.Add(inputAnnotations, null);
// after
builder.Add(inputAnnotations, name => true);
Defensive patterns

Strategy: validation

Validate before calling

if (selector == null)
    selector = name => true;
builder.Add(sourceAnnotations, selector);

Try / catch

try { builder.Add(annotations, selector); }
catch (ArgumentNullException e) when (e.ParamName == "selector")
{
    builder.Add(annotations, _ => true);
}

Prevention

When it happens

Trigger: Calling builder.Add(sourceAnnotations, null); forwarding a selector variable that is null because an upstream branch never assigned it; generic helper code that passes through an optional predicate without defaulting it.

Common situations: Writing a custom IDataView transform that copies a subset of annotations and mistakenly believing null means 'copy all'; refactoring where a previously always-set lambda became conditionally null.

Related errors


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