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

  1. Read the 'Targets' string[] property instead of 'Target': attribute.Targets.Contains(methodName).
  2. When writing new attributes, set [Benchmark(Target = "Foo")] is fine for input; just never call the getter.
  3. 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

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


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