dotnet/BenchmarkDotNet · info · InvalidOperationException
Please use Targets property
Error message
Please use Targets property
What it means
TargetedAttribute is the base class for targeting attributes such as [Benchmark]. The library migrated the single-method 'Target' string property to a 'Targets' string[] array. The 'Target' getter is preserved only because C# attribute syntax requires a read-write property pair; calling the getter throws to redirect consumers to the 'Targets' array. The setter still works (it splits on ',' and stores into Targets) for backward compatibility.
Source
Thrown at src/BenchmarkDotNet.Annotations/Attributes/TargetedAttribute.cs:17
using System.Reflection;
namespace BenchmarkDotNet.Attributes
{
/// <summary>
/// Base class for attributes that are targeted at one or more method(s)
/// </summary>
public abstract class TargetedAttribute : Attribute
{
public string[] Targets { get; set; } = [];
/// <summary>
/// Target method for attribute
/// </summary>
public string Target
{
get => throw new InvalidOperationException("Please use Targets property"); // kept to keep compiler happy "Named attribute arguments must be fields which are not readonly, static, or const, or read-write properties which are public and not static."
set => Targets = string.IsNullOrEmpty(value) ? [] : value.Split(','); // , is for backward compat
}
public bool Match(MethodInfo method) => Targets.Length == 0 || Targets.Contains(method.Name);
}
}
View on GitHub (pinned to b515068b61)
Solutions
- Read the 'Targets' string[] property instead of 'Target': attribute.Targets.Contains(methodName).
- When writing new attributes, set [Benchmark(Target = "Foo")] is fine for input; just never call the getter.
- If reflecting, filter for the 'Targets' property name and skip 'Target'.
Example fix
// before
var name = ((TargetedAttribute)attr).Target; // throws
// after
var names = ((TargetedAttribute)attr).Targets;
var match = names.Length == 0 || names.Contains("MyMethod"); Defensive patterns
Strategy: validation
Validate before calling
// Before reading, branch on Targets and never touch the Target getter:
static bool IsTargeted(TargetedAttribute attr, string methodName)
=> attr.Targets.Length == 0 || attr.Targets.Contains(methodName); Prevention
- Never read attribute.Target; only set it (via attribute syntax) or read attribute.Targets.
- When reflecting over attributes, special-case the string 'Target' to skip its getter.
When it happens
Trigger: Programmatically reading the 'Target' property via reflection at runtime (e.g. typeof(X).GetCustomAttributes().Target, or iterating attribute properties). Happens in custom tooling that inspects [Benchmark] / [ParamsSource]-style targeted attributes, or in code ported from an older BDN version that read '.Target'.
Common situations: Upgrading BenchmarkDotNet past the Target->Targets rename while keeping code that accesses the old single-value property; building analyzers/utilities that reflect over benchmark attributes.
Related errors
- Field 'ConsoleRunnerPackage' not found.
- Unable to get value of 'ConsoleRunnerPackage'.
- Method 'GetRunnerPath' not found.
- Unable to invoke 'GetRunnerPath'.
- Field 'ConsoleRunnerPackage' not found.
AI-assisted analysis of dotnet/BenchmarkDotNet@b515068b61 (2026-08-13).
Data as JSON: /api/errors/defe1e130f91c236.
Report an issue: GitHub.