dotnet/csharplang · error · ArgumentException
Index must not be negative.
Error message
Index must not be negative.
What it means
Thrown by the `System.Index` constructor (shown in the C# 8.0 ranges proposal, and shipped in the BCL) when the `value` argument is negative. `Index` stores either a forward offset or a from-end offset encoded via bitwise complement, so a negative `value` is not representable and is rejected up front. The implicit `int -> Index` conversion routes through this constructor, so a negative int passed where an Index is expected also throws.
Source
Thrown at proposals/csharp-8.0/ranges.cs:12
namespace System
{
public readonly struct Index
{
private readonly int _value;
public int Value => _value < 0 ? ~_value : _value;
public bool FromEnd => _value < 0;
public Index(int value, bool fromEnd)
{
if (value < 0) throw new ArgumentException("Index must not be negative.", nameof(value));
_value = fromEnd ? ~value : value;
}
public static implicit operator Index(int value)
=> new Index(value, fromEnd: false);
}
public readonly struct Range
{
public Index Start { get; }
public Index End { get; }
private Range(Index start, Index end)
{
this.Start = start;
this.End = end;
}View on GitHub (pinned to 05eb4800fc)
Solutions
- Guard the computed value before constructing the Index: `if (i < 0) throw/handle`.
- Use the from-end form for end-relative positions: write `^n` (or `new Index(n, fromEnd: true)`) instead of `length - n`, which avoids negative intermediates.
- Clamp the value to >= 0 when a non-negative fallback is acceptable.
- Replace -1 sentinel returns from upstream code with nullable or Option-style results before they reach Index construction.
Example fix
// before
Index idx = i - span.Length; // throws if i < span.Length
// after
Index idx = i >= 0 ? new Index(i, fromEnd: false)
: throw new ArgumentOutOfRangeException(nameof(i)); Defensive patterns
Strategy: validation
Validate before calling
static Index SafeIndex(int value, bool fromEnd = false)
{
if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Index must not be negative.");
return new Index(value, fromEnd);
} Type guard
static bool IsValidIndexValue(int value) => value >= 0;
Try / catch
try { Index idx = computed; }
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == nameof(computed))
{
// fall back to ^0 or recompute from the collection length
} Prevention
- Prefer the `^n` from-end syntax for end-relative positions to avoid negative intermediates.
- Guard any subtraction that feeds an Index: `if (i < 0) ...`.
- Never pipe -1 sentinel returns directly into Index-taking APIs; convert them first.
When it happens
Trigger: `new Index(-1, fromEnd: false)`, implicit conversion of a negative int to `Index`, or handing a computed offset that subtracted past zero into any API taking `Index` (e.g. `array[^...]`, slicing helpers).
Common situations: Subtraction like `position - length` that goes negative; loop indices that underflow; converting a 'from end' count incorrectly; interop with code that returns -1 as a sentinel and feeding it straight into an Index-taking API.
Related errors
- {argumentExpression} ({argument}) cannot be less than {lowEx
- {argumentExpression} ({argument}) cannot be greater than {hi
- Array must contain a single element.
- Empty names not allowed
AI-assisted analysis of dotnet/csharplang@05eb4800fc (2026-08-13).
Data as JSON: /api/errors/2cfac3753ed66b30.
Report an issue: GitHub.