dotnet/machinelearning · error · ArgumentException

getter must be of type '{typeof(ValueGetter<TValue>).FullNam

Error message

getter must be of type '{typeof(ValueGetter<TValue>).FullName}'

What it means

Builder.AddDelegate casts the getter delegate to ValueGetter<TValue> and throws ArgumentException("getter must be of type 'ValueGetter<TValue>'") when the cast fails. The builder requires a typed ValueGetter<TValue> delegate to store values into the schema column; any other delegate signature cannot be used. Note the Debug.Asserts indicate this method is internal/contractually pre-validated, so this mostly surfaces from dynamic invocation.

Source

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

                /// Returns a <see cref="Annotations"/> row that contains the current contents of this <see cref="Builder"/>.
                /// </summary>
                public Annotations ToAnnotations()
                {
                    var builder = new DataViewSchema.Builder();
                    foreach (var item in _items)
                        builder.AddColumn(item.Name, item.Type, item.Annotations);
                    return new Annotations(builder.ToSchema(), _items.Select(x => x.Getter).ToArray());
                }

                private void AddDelegate<TValue>(string name, DataViewType type, Delegate getter, Annotations annotations)
                {
                    Debug.Assert(!string.IsNullOrEmpty(name));
                    Debug.Assert(type != null);
                    Debug.Assert(getter != null);

                    var typedGetter = getter as ValueGetter<TValue>;
                    if (typedGetter == null)
                        throw new ArgumentException($"{nameof(getter)} must be of type '{typeof(ValueGetter<TValue>).FullName}'", nameof(getter));
                    _items.Add((name, type, typedGetter, annotations));
                }
            }
        }

        /// <summary>
        /// Class containing operations to build a <see cref="DataViewSchema"/>.
        /// </summary>
        public sealed class Builder
        {
            private readonly List<(string Name, DataViewType Type, Annotations Annotations)> _items;

            /// <summary>
            /// Create a new instance of <see cref="Builder"/>.
            /// </summary>
            public Builder()
            {
                _items = new List<(string Name, DataViewType Type, Annotations Annotations)>();

View on GitHub (pinned to 7b76e69cf9)

Solutions

  1. Supply a ValueGetter<TValue> delegate: (ref TValue dst) => dst = value, not Func/Action with different signatures.
  2. Ensure the generic type argument matches the getter's type argument (ValueGetter<int> for TValue=int).
  3. When using reflection, call Delegate.CreateDelegate(typeof(ValueGetter<T>), target, method) with the correct T.
  4. Cast defensively: if (getter is ValueGetter<TValue> g) builder.AddDelegate(...) else throw a clear error.

Example fix

// before
builder.AddDelegate("Score", NumberDataViewType.Single, (float) => GetScore());
// after
float GetScore(ref float dst) { dst = ComputeScore(); }
builder.AddDelegate("Score", NumberDataViewType.Single, (ValueGetter<float>)GetScore);
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(getter is ValueGetter<TValue>)) throw new ArgumentException("getter must be a ValueGetter<TValue>");

Type guard

bool IsTypedGetter<TV>(Delegate d) => d is ValueGetter<TV>;

Try / catch

try { builder.AddDelegate(name, type, getter); } catch (ArgumentException) { /* rebuild delegate as ValueGetter<TValue> */ }

Prevention

When it happens

Trigger: Passing a lambda or method group convertible to Func<TValue> but not to ValueGetter<TValue> (whose signature is void(ref TValue)), e.g. AddDelegate(name, type, (out int v) => ...) or a Delegate obtained via reflection/Delegate.CreateDelegate with the wrong signature.

Common situations: Reflection-based schema construction where the delegate was created against the wrong generic type argument; wrapping existing getters with incompatible anonymous delegates; generic helpers passing Delegate objects.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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