dotnet/BenchmarkDotNet · error · InvalidOperationException

The argument must be an array of primitives

Error message

The argument must be an array of primitives

What it means

The final guard in ArrayParam.FromObject: SourceCodeHelper.IsCompilationTimeConstant must return true for the element type. That helper accepts only primitives (int/long/byte/...), bool, string, char, float, double, decimal, enums, Type, TimeInterval, IntPtr and DateTime. Any other element type (a custom class/struct, a record, etc.) causes it to throw because BDN cannot emit it as a compile-time literal in the generated harness.

Source

Thrown at src/BenchmarkDotNet/Code/ArrayParam.cs:77

        /// <summary>
        /// for types where calling .ToString() will be NOT enough to re-create them in auto-generated source code file
        /// </summary>
        /// <param name="array">the array</param>
        /// <param name="toSourceCode">method which transforms an item of type T to it's C# representation
        /// example: point => $"new Point2d({point.X}, {point.Y})"
        /// </param>
        [PublicAPI] public static ArrayParam<T> ForComplexTypes(T[] array, Func<T, string> toSourceCode) => new ArrayParam<T>(array, toSourceCode);

        internal static IParam? FromObject(object array)
        {
            var type = array.GetType();
            if (!type.IsArray)
                throw new InvalidOperationException("The argument must be an array");
            var elementType = type.GetElementType();
            if (elementType == null)
                throw new InvalidOperationException("Failed to determine type of array elements");
            if (!SourceCodeHelper.IsCompilationTimeConstant(elementType))
                throw new InvalidOperationException("The argument must be an array of primitives");

            var arrayParamType = typeof(ArrayParam<>).MakeGenericType(elementType);

            var methodInfo = arrayParamType.GetMethod(nameof(ForPrimitives), BindingFlags.Public | BindingFlags.Static)
                ?? throw new InvalidOperationException($"{nameof(ForPrimitives)} not found");
            return (IParam?)methodInfo.Invoke(null, [array]);
        }
    }
}

View on GitHub (pinned to b515068b61)

Solutions

  1. For complex element types use ArrayParam<T>.ForComplexTypes(array, item => $"new T(...)") and expose it via a custom IParam, which gives BDN the source-code rendering function.
  2. Decompose the complex type into primitive arrays that BDN can emit.
  3. If the type is actually a primitive-compatible enum/Type, make sure its element Type is the enum/Type itself, not a wrapper.
  4. Avoid passing object[] of mixed complex types; use a dedicated params source with a custom IParam.

Example fix

// before
[Arguments(new Point[] { new Point(1,2) })]
public void B(Point[] pts) { }

// after
public void B([ParamsSource(nameof(Pts))] Point[] pts) { /* supply via ArrayParam.ForComplexTypes in an IParam */ }
Defensive patterns

Strategy: validation

Validate before calling

var elementType = array.GetType().GetElementType();
if (elementType is null || !SourceCodeHelper.IsCompilationTimeConstant(elementType))
    return ArrayParam<object>.ForComplexTypes(
        ((IEnumerable<object>)array).ToArray(),
        item => item?.ToString() ?? "null");
return ArrayParam.FromObject(array);

Type guard

static bool ElementIsPrimitive(Array a)
    => a.GetType().GetElementType() is Type t && SourceCodeHelper.IsCompilationTimeConstant(t);

Try / catch

try { return ArrayParam.FromObject(obj); }
catch (InvalidOperationException ex) when (ex.Message.Contains("array of primitives"))
{
    // use ArrayParam<T>.ForComplexTypes with a toSourceCode delegate instead
}

Prevention

When it happens

Trigger: Declaring an array argument whose element type is a custom class, struct, record, or any non-primitive/non-enum reference type, and routing it through FromObject (the default path for [Arguments]/[Params] arrays of primitives).

Common situations: [Arguments(new[] { new MyStruct(...) })] with a user-defined type, arrays of complex DTOs, or arrays of nullable wrappers.

Related errors


AI-assisted analysis of dotnet/BenchmarkDotNet@b515068b61 (2026-08-13). Data as JSON: /api/errors/343d0d4d37177a45. Report an issue: GitHub.