dotnet/machinelearning · error · ArgumentException

type.RawType must be of type '{typeof(TValue).FullName}'.

Error message

type.RawType must be of type '{typeof(TValue).FullName}'.

What it means

Builder.Add<TValue> enforces that the DataViewType's RawType equals typeof(TValue): the static generic parameter and the declared logical type must agree, otherwise the ValueGetter<TValue> would read the wrong CLR representation. Mismatch throws ArgumentException naming 'type'.

Source

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

                /// <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)
                {
                    if (string.IsNullOrEmpty(name))
                        throw new ArgumentNullException(nameof(name));
                    if (type == null)
                        throw new ArgumentNullException(nameof(type));
                    if (getter == null)
                        throw new ArgumentNullException(nameof(getter));
                    if (type.RawType != typeof(TValue))
                        throw new ArgumentException($"{nameof(type)}.{nameof(type.RawType)} must be of type '{typeof(TValue).FullName}'.", nameof(type));

                    _items.Add((name, type, getter, annotations));
                }

                /// <summary>
                /// Add one annotation column, weakly-typed version.
                /// </summary>
                /// <param name="name">The annotation name.</param>
                /// <param name="type">The annotation type.</param>
                /// <param name="getter">The getter delegate that provides the value. Note that the type of the getter is still checked
                /// inside this method.</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(string name, DataViewType type, Delegate getter, Annotations annotations = null)
                {
                    if (string.IsNullOrEmpty(name))
                        throw new ArgumentNullException(nameof(name));
                    if (type == null)

View on GitHub (pinned to 7b76e69cf9)

Solutions

  1. Set TValue to exactly column.Type.RawType (or the well-known annotation type, e.g. VBuffer<ReadOnlyMemory<char>> for SlotNames)
  2. Derive the getter's generic type from the type first, then call the weakly-typed Add(name, type, Delegate) overload which marshals via MarshalActionInvoke
  3. Use AnnotationUtils/TypeUtils helpers that pick the correct TValue per DataViewType

Example fix

// before
builder.Add<VBuffer<float>>("SlotNames", NumberDataViewType.Single, getter);
// after
builder.Add<float>("SlotNames", NumberDataViewType.Single, getter); // TValue matches RawType
// or for vectors:
builder.Add<VBuffer<float>>("Features", new VectorDataViewType(NumberDataViewType.Single), getter);
Defensive patterns

Strategy: type-guard

Validate before calling

if (type.RawType != typeof(TValue))
    throw new InvalidOperationException($"Use TValue={type.RawType.Name} for type {type}");
builder.Add(name, type, getter);

Type guard

bool TypeMatches<TValue>(DataViewType t) => t.RawType == typeof(TValue);

Try / catch

try { builder.Add<TValue>(name, type, getter); }
catch (ArgumentException e) when (e.ParamName == "type")
{
    // fall back to weakly-typed dispatch
    builder.Add(name, type, (Delegate)getter);
}

Prevention

When it happens

Trigger: Adding a column typed as VBuffer<float> while TValue is float[]; using NumberDataViewType.Double (RawType double) with a ValueGetter<float>; key types whose RawType is uint paired with an int getter.

Common situations: Generic helper code that fixes TValue at compile time but receives arbitrary DataViewTypes at runtime; copy-pasted annotation code (e.g. slot names use VBuffer<ReadOnlyMemory<char>>) adapted to scalar columns without changing TValue.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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