dotnet/wpf · error · ArgumentException

SR.Format(SR.RemoveRequiresOffsetZero, position.Index…

Error message

SR.Format(SR.RemoveRequiresOffsetZero, position.Index, position.Offset)

What it means

ItemContainerGenerator.Remove (and Recycle) requires the GeneratorPosition to have Offset == 0, meaning it points exactly at a realized item. A non-zero offset would refer to a point between items or an unrealized slot, which Remove cannot resolve, so it throws ArgumentException naming the offending index and offset.

Solutions

  1. Normalize the GeneratorPosition so Offset is 0 before calling Remove (use GeneratorPositionFromIndex on a realized index).
  2. Verify the item is realized (ContainerFromIndex returns non-null) before removing; use Recycle-like semantics otherwise.
  3. If removing everything, call RemoveAllInternal/RemoveAll instead of looping manual Remove calls.

Example fix

// before
var pos = generator.GeneratorPositionFromIndex(i);
if (pos.Offset != 0) generator.Remove(pos, 1, true); // throws

// after
var pos = generator.GeneratorPositionFromIndex(i);
if (pos.Offset == 0)
    generator.Remove(pos, 1, true);
else
    generator.Remove(new GeneratorPosition(pos.Index + 1, 0), 1, true); // adjust to realized boundary
Defensive patterns

Strategy: validation

Validate before calling

var pos = generator.GeneratorPositionFromIndex(i);
if (pos.Offset != 0)
    throw new ArgumentException("Remove requires a realized position (Offset == 0)");
if (count > 0)
    generator.Remove(pos, count, isRecycling);

Type guard

static bool IsRealizedPosition(GeneratorPosition p) => p.Offset == 0;

Try / catch

try { generator.Remove(pos, count, true); }
catch (ArgumentException ex) when (ex.ParamName == "position")
{
    // re-derive a normalized position and retry
}

Prevention

When it happens

Trigger: Calling IItemContainerGenerator.Remove(position, count, isRecycling) with a position whose Offset is non-zero (e.g. a position obtained for a spot inside a group or from IndexOf on an unrealized item).

Common situations: Custom panels computing positions by hand and forgetting that Remove needs positions normalized to realized containers; mixing positions meant for RemoveAllInternal with manual Remove calls.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/5b539df0eb71f132. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ItemContainerGenerator.cs:272

            object item = container.ReadLocalValue(ItemForItemContainerProperty);
            Host.PrepareItemContainer(container, item);
        }

        /// <summary>
        /// Remove generated elements.
        /// </summary>
        void IItemContainerGenerator.Remove(GeneratorPosition position, int count)
        {
            Remove(position, count, /*isRecycling = */ false);
        }

        /// <summary>
        /// Remove generated elements.
        /// </summary>
        private void Remove(GeneratorPosition position, int count, bool isRecycling)
        {
            if (position.Offset != 0)
                throw new ArgumentException(SR.Format(SR.RemoveRequiresOffsetZero, position.Index, position.Offset), nameof(position));
            if (count <= 0)
                throw new ArgumentException(SR.Format(SR.RemoveRequiresPositiveCount, count), nameof(count));

            if (_itemMap == null)
            {
                // ignore reentrant call (during RemoveAllInternal)
                Debug.Fail("Unexpected reentrant call to ICG.Remove");
                return;
            }

            int index = position.Index;
            ItemBlock block;

            // find the leftmost item to remove
            int offsetL = index;
            for (block = _itemMap.Next;  block != _itemMap;  block = block.Next)
            {
                if (offsetL < block.ContainerCount)

View on GitHub (pinned to 81131a70a4)