iOfficeAI/OfficeCLI · error · ArgumentException

{cellRef} spans multiple {(char.IsDigit(cellRef[0]) ? "rows"

Error message

{cellRef} spans multiple {(char.IsDigit(cellRef[0]) ? "rows" : "columns")} — get them one at a time ({axisSegments[0]} … {axisSegments[^1]}); set accepts the whole span.

What it means

Thrown when a GET request uses a multi-axis span reference such as B:D (columns) or 1:5 (rows). TryExpandAxisRef accepts Excel-style whole-axis refs, but a span covering more than one column or row has no single node to return from Get. Single-axis aliases (B:B, 1:1) are re-dispatched to col[B]/row[1]; multi-axis spans are rejected and the message points at the bracket/set syntax that does accept a range.

Source

Thrown at src/officecli/Handlers/Excel/ExcelHandler.Query.cs:906

                    ?? throw new ArgumentException(
                        $"Shape[{shpIndex}] not found in sheet '{sheetNameFromPath}' (indices are 1-based).");
            }


            // If it looks like it could be a malformed cell reference (digits only, etc.), reject it
            if (Regex.IsMatch(cellRef, @"^\d+$"))
                throw new ArgumentException($"Invalid cell reference: '{cellRef}'. Expected format like 'A1', 'B2'.");

            // CONSISTENCY(axis-ref-compat): Excel-style whole-column/row
            // references (B:B, 1:1) are input aliases for col[X]/row[N] —
            // re-dispatch a single-axis span to the canonical path (readback
            // Path stays canonical). Multi-axis spans (B:D) have no single
            // node to return; point at the bracket syntax instead.
            if (TryExpandAxisRef(cellRef) is { } axisSegments)
            {
                if (axisSegments.Count == 1)
                    return Get($"/{sheetNameFromPath}/{axisSegments[0]}", depth);
                throw new ArgumentException(
                    $"{cellRef} spans multiple {(char.IsDigit(cellRef[0]) ? "rows" : "columns")} — get them one at a time ({axisSegments[0]} … {axisSegments[^1]}); set accepts the whole span.");
            }

            // Generic XML fallback: navigate worksheet XML tree
            var xmlSegments = GenericXmlQuery.ParsePathSegments(cellRef);
            var target = GenericXmlQuery.NavigateByPath(GetSheet(worksheet), xmlSegments);
            if (target == null)
                return new DocumentNode { Path = path, Type = "error", Text = $"Element not found: {cellRef}" };
            return GenericXmlQuery.ElementToNode(target, path, depth);
        }

        // Handle /SheetName/A1/run[N] (rich text run direct access)
        var runGetMatch = Regex.Match(cellRef, @"^([A-Z]+\d+)/run\[(\d+)\]$", RegexOptions.IgnoreCase);
        if (runGetMatch.Success)
        {
            var runCellRef = runGetMatch.Groups[1].Value.ToUpperInvariant();
            var runIdx = int.Parse(runGetMatch.Groups[2].Value);
            ParseCellReference(runCellRef);

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Get each axis member individually: get /Sheet1/B then /Sheet1/C then /Sheet1/D.
  2. Use the bracket selector for a range query: get /Sheet1/row[1:5] or query the column range via the col[] selector form.
  3. If you need to write the span, use Set (set /Sheet1/B:D ...) which accepts the whole span.

Example fix

// before
get /Sheet1/B:D
// after
get /Sheet1/B
get /Sheet1/C
get /Sheet1/D
Defensive patterns

Strategy: validation

Validate before calling

def is_multi_axis_span(seg):
    # B:D or 1:5 style spans that cover >1 member are not gettable as one node
    if ':' not in seg: return False
    parts = seg.split(':')
    if len(parts) != 2: return False
    # same-type endpoints spanning more than one unit
    return parts[0] != parts[1]

# before a GET
seg = 'B:D'
assert not is_multi_axis_span(seg), 'GET needs one node; iterate members or use Set for the span'

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: get /Sheet1/B:D, get /Sheet1/1:5, or any colon-span whose TryExpandAxisRef yields more than one segment. Triggered only on the read (Get) path — Set accepts the whole span.

Common situations: Treating Get like Set (Set tolerates ranges); pasting an Excel range selection (B:D) straight into a get path; assuming Get returns a list for a span when it is designed to return one node.

Related errors


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