iOfficeAI/OfficeCLI · error · ArgumentException

{axis} field '{fieldRef}' (index {idx}) is out of range afte

Error message

{axis} field '{fieldRef}' (index {idx}) is out of range after source narrowing to {newFieldCount} column(s). Restate {axis}= in the same Set call to drop or reassign it.

What it means

Thrown by the R15-2 validation in RefreshPivotCacheFromSource: when the new source range has fewer columns than the old one, existing pivot field indices (value/row/col/filter) may point past the new header list. Rather than silently clamping or dropping those fields — which would leave DataFields pointing past columnData and crash RenderPivotIntoSheet with ArgumentOutOfRangeException — the code rejects the operation. Axes that the SAME Set call is explicitly overwriting (rows=/cols=/values=/filters=) are excluded from this check because their new values will be re-parsed against fresh headers.

Source

Thrown at src/officecli/Core/PivotTableHelper.Readback.cs:442

        // crashing RenderPivotIntoSheet with ArgumentOutOfRangeException.
        // Prefer strict error over data loss: user must explicitly restate the
        // affected axes in the same Set call if they intended to drop them.
        var newFieldCount = headers.Length;
        var existingPivotDef = pivotPart.PivotTableDefinition;
        if (existingPivotDef != null)
        {
            // Axes that the same Set call is explicitly overwriting are
            // excluded from validation — their new values will be parsed
            // against the fresh headers by RebuildFieldAreas.
            bool rowsOverwritten = pendingFieldAreaProps?.ContainsKey("rows") == true;
            bool colsOverwritten = pendingFieldAreaProps?.ContainsKey("cols") == true;
            bool valuesOverwritten = pendingFieldAreaProps?.ContainsKey("values") == true;
            bool filtersOverwritten = pendingFieldAreaProps?.ContainsKey("filters") == true;

            void ValidateIndex(int idx, string axis, string fieldRef)
            {
                if (idx >= newFieldCount)
                    throw new ArgumentException(
                        $"{axis} field '{fieldRef}' (index {idx}) is out of range " +
                        $"after source narrowing to {newFieldCount} column(s). " +
                        $"Restate {axis}= in the same Set call to drop or reassign it.");
            }
            if (!valuesOverwritten && existingPivotDef.DataFields != null)
            {
                foreach (var df in existingPivotDef.DataFields.Elements<DataField>())
                {
                    var fi = (int)(df.Field?.Value ?? 0);
                    ValidateIndex(fi, "value", df.Name?.Value ?? fi.ToString());
                }
            }
            if (!rowsOverwritten && existingPivotDef.RowFields != null)
            {
                foreach (var f in existingPivotDef.RowFields.Elements<Field>())
                {
                    var fi = f.Index?.Value ?? -1;
                    if (fi >= 0) ValidateIndex(fi, "row", fi.ToString());

View on GitHub (pinned to 1ced45e900)

Solutions

  1. In the same Set call, restate the affected axis to point at a column that exists in the new range: e.g. Set pivot source=Sheet1!A1:B10 values=ColB.
  2. Widen the source range so existing field indices still fit within the new column count.
  3. Explicitly drop the axis by setting it to empty if you intend to remove it.
  4. Check the new header count first (Get source headers) and compare against the pivot's current field assignments.

Example fix

// before — pivot has values=Amount (index 3), narrowing to 2 cols fails
Set pivot source=Sheet1!A1:B10
// after — restate values in the same call
Set pivot source=Sheet1!A1:B10 values=ColB
Defensive patterns

Strategy: validation

Validate before calling

// Before narrowing a source, compare existing field indices against the new column count
var (newHeaders, _, _) = ReadSourceData(sourceWsPart, newRange);
int newFieldCount = newHeaders.Length;
foreach (var df in pivotDef.DataFields?.Elements<DataField>() ?? Enumerable.Empty<DataField>())
{
    if ((int)(df.Field?.Value ?? 0) >= newFieldCount && !restattingValues)
        throw new ArgumentException($"Data field index {(int)(df.Field?.Value ?? 0)} exceeds new column count {newFieldCount}. Restate values= in the same Set call.");
}

Prevention

When it happens

Trigger: Calling Set source=Sheet1!A1:B10 on a pivot that currently has values=ColD (index 3) when the new range only has 2 columns — and values= is NOT also passed in the same call. The existing DataField at index 3 exceeds the new field count of 2.

Common situations: Narrowing a pivot's source from a wide range to a narrow one without restating which fields go on each axis; dropping columns from the source data while the pivot still references them; restructuring a data table to fewer columns.

Related errors


AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13). Data as JSON: /api/errors/33ce51e501478f06. Report an issue: GitHub.