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
- 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.
- Decompose the complex type into primitive arrays that BDN can emit.
- If the type is actually a primitive-compatible enum/Type, make sure its element Type is the enum/Type itself, not a wrapper.
- 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
- Keep [Arguments]/[Params] array elements to primitives, enums, string, or Type.
- For complex element types, supply a custom IParam via ArrayParam<T>.ForComplexTypes(array, item => $"...").
- Decompose complex types into primitive arrays when possible.
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
- The argument must be an array
- Failed to determine type of array elements
- There is no default resolver for {characteristic.FullId}
- The current object {this} is frozen. Create a copy to modify
- The current operation allowed for root nodes only, but the v
AI-assisted analysis of dotnet/BenchmarkDotNet@b515068b61 (2026-08-13).
Data as JSON: /api/errors/343d0d4d37177a45.
Report an issue: GitHub.