dotnet/csharplang · error · ArgumentException

Array must contain a single element.

Error message

Array must contain a single element.

What it means

Thrown by an illustrative `Single<T>(this T[] array)` extension method when the supplied array does not contain exactly one element. The check is shown in the caller-argument-expression proposal as the 'traditional' argument-validation style that the feature is meant to reduce. A null array is handled separately by ArgumentNullException; this exception is specifically the length != 1 case.

Source

Thrown at proposals/csharp-10.0/caller-argument-expression.md:43

```

When one of the asserts fail, only the filename, line number, and method name will be provided in the stack trace. The developer will not be able to tell which assert failed from this information-- they will have to open the file and navigate to the provided line number to see what went wrong.

This is also the reason testing frameworks have to provide a variety of assert methods. With xUnit, `Assert.True` and `Assert.False` are not frequently used because they do not provide enough context about what failed.

While the situation is a bit better for argument validation because the names of invalid arguments are shown to the developer, the developer must pass these names to exceptions manually. If the above example were rewritten to use traditional argument validation instead of `Debug.Assert`, it would look like

```csharp
T Single<T>(this T[] array)
{
    if (array == null)
    {
        throw new ArgumentNullException(nameof(array));
    }

    if (array.Length != 1)
    {
        throw new ArgumentException("Array must contain a single element.", nameof(array));
    }

    return array[0];
}
```

Notice that `nameof(array)` must be passed to each exception, although it's already clear from context which argument is invalid.

## Detailed design
[design]: #detailed-design

In the above examples, including the string `"array != null"` or `"array.Length == 1"` in the assert message would help the developer determine what failed. Enter `CallerArgumentExpression`: it's an attribute the framework can use to obtain the string associated with a particular method argument. We would add it to `Debug.Assert` like so

```csharp
public static class Debug
{
    public static void Assert(bool condition, [CallerArgumentExpression("condition")] string message = null);
}

View on GitHub (pinned to 05eb4800fc)

Solutions

  1. Guarantee exactly one element before calling Single: check `array.Length == 1` (or use LINQ `Single()` only after confirming one match).
  2. If zero-or-one is acceptable, switch to a FirstOrDefault-style read and handle the null/missing case explicitly.
  3. If multiple is acceptable, use First/Last or index `array[0]` after a length guard.
  4. Fix the upstream producer so it cannot emit an empty or multi-element array.

Example fix

// before
T value = array.Single<T>();

// after
if (array is null) throw new ArgumentNullException(nameof(array));
if (array.Length != 1) throw new ArgumentException("Array must contain a single element.", nameof(array));
T value = array[0];
Defensive patterns

Strategy: validation

Validate before calling

static T SafeSingle<T>(T[] array)
{
    if (array is null) throw new ArgumentNullException(nameof(array));
    if (array.Length != 1)
        throw new InvalidOperationException($"Expected exactly one element, got {array.Length}.");
    return array[0];
}

Type guard

static bool HasSingle<T>(T[] array) => array is { Length: 1 };

Try / catch

try { T value = array.Single(); }
catch (InvalidOperationException ex) when (array is null || array.Length != 1)
{
    // log and apply single-or-default fallback
}

Prevention

When it happens

Trigger: Calling `array.Single()` on an array whose Length is 0 (empty) or >= 2. Passing a collection that has been filtered/cleared so it no longer has exactly one item.

Common situations: LINQ-style Single usage on results of a query that returned zero or multiple matches; defensive code that assumes a singleton array after deserialization; arrays whose contents were mutated between population and the Single call.

Related errors


AI-assisted analysis of dotnet/csharplang@05eb4800fc (2026-08-13). Data as JSON: /api/errors/ae826b3753f155cd. Report an issue: GitHub.