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

  1. Clamp the count to at least 0 (Math.Max(0, count)) before constructing the result.
  2. Return RenderPickingResult.NoOperation (the default) when no picking indices are produced.
  3. 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

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


AI-assisted analysis of Unity-Technologies/UnityCsReference@225b0fbdb5 (2026-08-13). Data as JSON: /api/errors/ac5f58a3c36d465c. Report an issue: GitHub.