Unity-Technologies/UnityCsReference · error · ArgumentOutOfRangeException
The value ({renderedPickingIndexCount}) must not be negative
Error message
The value ({renderedPickingIndexCount}) must not be negative What it means
The RenderPickingResult constructor validates that renderedPickingIndexCount is non-negative; a negative count would break the picking-index arithmetic used to map a picked sub-mesh index back to a handle, so it throws ArgumentOutOfRangeException. Both constructor overloads apply the same guard, since the count is independent of which resolver callback is supplied.
Source
Thrown at Editor/Mono/Handles/HandleUtility.cs:102
{
var contained = RenderObjectSetContainsObject(obj);
return renderPickingType == RenderPickingType.RenderFromFilterSet ? contained : !contained;
}
}
public readonly struct RenderPickingResult
{
public int renderedPickingIndexCount { get; }
public HandleUtility.ResolvePickingCallback resolver { get; }
public HandleUtility.ResolvePickingWithWorldPositionCallback resolverWithWorldPos { get; }
[NoAutoStaticsCleanup] // default struct value; no mutable state
public static readonly RenderPickingResult NoOperation = default;
public RenderPickingResult(int renderedPickingIndexCount, HandleUtility.ResolvePickingCallback resolver)
{
if (renderedPickingIndexCount < 0)
throw new ArgumentOutOfRangeException(nameof(renderedPickingIndexCount), $"The value ({renderedPickingIndexCount}) must not be negative");
if (resolver == null)
throw new ArgumentNullException(nameof(resolver));
this.renderedPickingIndexCount = renderedPickingIndexCount;
this.resolver = resolver;
this.resolverWithWorldPos = null;
}
public RenderPickingResult(int renderedPickingIndexCount, HandleUtility.ResolvePickingWithWorldPositionCallback resolver)
{
if (renderedPickingIndexCount < 0)
throw new ArgumentOutOfRangeException(nameof(renderedPickingIndexCount), $"The value ({renderedPickingIndexCount}) must not be negative");
if (resolver == null)
throw new ArgumentNullException(nameof(resolver));
this.renderedPickingIndexCount = renderedPickingIndexCount;
this.resolverWithWorldPos = resolver;
this.resolver = null;View on GitHub (pinned to 225b0fbdb5)
Solutions
- Clamp the count to at least 0 (Math.Max(0, count)) before constructing the result.
- Return RenderPickingResult.NoOperation (the default) when no picking indices are produced.
- Audit the control-ID allocation arithmetic to ensure the count reflects actually rendered handles.
Example fix
// before return new RenderPickingResult(nextControlId - firstControlId, Resolve); // after int count = Math.Max(0, nextControlId - firstControlId); return count == 0 ? RenderPickingResult.NoOperation : new RenderPickingResult(count, Resolve);
Defensive patterns
Strategy: validation
Validate before calling
int count = Math.Max(0, nextControlId - firstControlId); if (count == 0) return RenderPickingResult.NoOperation; return new RenderPickingResult(count, Resolve);
Type guard
static bool IsValidPickingCount(int count) => count >= 0;
Prevention
- Clamp picking counts to >= 0.
- Return RenderPickingResult.NoOperation for zero-index cases.
- Verify control-ID allocation arithmetic in custom handles.
When it happens
Trigger: Constructing a RenderPickingResult with a negative count, e.g. subtracting control counts and underflowing; passing an uninitialized int field; computing the count from a mesh that failed to render.
Common situations: Custom editor handle implementing picking via RenderPickingResult; arithmetic that yields -1 when no handle control IDs are allocated; stale/zeroed buffers after a domain reload.
Related errors
- resolver
- Invalid argument: {dropPosition}
- Duplicating Assets is unsupported by this function. Use Asse
- The source path cannot be empty.
- Path cannot be null or empty.
AI-assisted analysis of Unity-Technologies/UnityCsReference@225b0fbdb5 (2026-08-13).
Data as JSON: /api/errors/ac5f58a3c36d465c.
Report an issue: GitHub.