iOfficeAI/OfficeCLI · error · ArgumentException

Invalid anchor: '{shpAnchorStr}'. Expected e.g. 'B2' or 'B2:

Error message

Invalid anchor: '{shpAnchorStr}'. Expected e.g. 'B2' or 'B2:F7'.

What it means

Thrown when the `anchor=` property (or the `ref=` alias mapped into `anchor`) is present but TryParseCellRangeAnchor cannot parse it as an A1-style cell or cell range. The parser only accepts the form `COLrow` or `COLrow:COLrow` (e.g. `B2`, `B2:F7`); anything else — a pixel value, a named range, an R1C1 string, an inverted or malformed token — fails the regex and throws. This is the cell-range grammar shared with OLE's anchor=, introduced for consistency across the drawing/cell/comment/table Add paths.

Source

Thrown at src/officecli/Handlers/Excel/ExcelHandler.Add.Drawings.cs:613

                // rectangle (B2:C3) so the shape has a visible extent.
                // Using identical from/to markers produces a
                // zero-width/height invisible shape in Excel.
                if (TryParseCellRangeAnchor(refTrim, out var rc, out var rr, out _, out _))
                    refTrim = $"{refTrim}:{IndexToColumnName(rc + 2)}{rr + 2}";
                else
                    refTrim = $"{refTrim}:{refTrim}";
            }
            properties["anchor"] = refTrim;
        }
        int sx, sy, sw, sh;
        if (properties.TryGetValue("anchor", out var shpAnchorStr) && !string.IsNullOrWhiteSpace(shpAnchorStr))
        {
            if (properties.ContainsKey("width") | properties.ContainsKey("height")
                | properties.ContainsKey("x") | properties.ContainsKey("y"))
                Console.Error.WriteLine(
                    "Warning: 'x'/'y'/'width'/'height' are ignored when 'anchor' is provided (anchor defines the full rectangle).");
            if (!TryParseCellRangeAnchor(shpAnchorStr, out var sxFrom, out var syFrom, out var sxTo, out var syTo))
                throw new ArgumentException($"Invalid anchor: '{shpAnchorStr}'. Expected e.g. 'B2' or 'B2:F7'.");
            sx = sxFrom;
            sy = syFrom;
            if (sxTo < 0) { sxTo = sx + 4; syTo = sy + 2; }
            sw = sxTo - sx;
            sh = syTo - sy;
        }
        else
        {
            (sx, sy, sw, sh) = ParseAnchorBounds(properties, "1", "1", "5", "3");
        }
        // Clamp the derived TwoCellAnchor span to Excel's grid so an
        // x/y/width/height that walks the TO marker past the ceiling ends at the
        // grid edge (what real Excel does) instead of being written out of range
        // into a file Excel refuses to open. FROM out of grid still throws.
        {
            var (shpToCol, shpToRow) = ClampAnchorSpan(sx, sy, sx + sw, sy + sh,
                shpAnchorStr ?? $"x={sx},y={sy},width={sw},height={sh}");
            sw = shpToCol - sx;

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Use the A1 cell-range form `anchor=B2` or `anchor=B2:F7`.
  2. If you meant pixel/column-unit coordinates, drop `anchor=` and use `x=`, `y=`, `width=`, `height=` instead (the else-branch ParseAnchorBounds handles those).
  3. If you supplied `ref=`, ensure it is a real cell address; `ref=` is aliased to `anchor=` for single-cell placement.

Example fix

// before
add ./book.xlsx /Sheet1 shape --type rectangle --prop anchor=100,100,200,80
// after
add ./book.xlsx /Sheet1 shape --type rectangle --prop anchor=B2:F7
Defensive patterns

Strategy: validation

Validate before calling

// Use the same parser the handler uses to pre-validate the anchor.
if (!ExcelHandler.TryParseCellRangeAnchor(anchorStr,
        out var fc, out var fr, out var tc, out var tr))
    throw new InvalidOperationException(
        $"anchor '{anchorStr}' must be like 'B2' or 'B2:F7'");

Type guard

static bool IsValidCellAnchor(string? s)
    => System.Text.RegularExpressions.Regex.IsMatch(
        s ?? "", @"^[A-Za-z]{1,3}\d+(:[A-Za-z]{1,3}\d+)?$");

Try / catch

try { handler.Add(...); }
catch (ArgumentException ex) when (ex.Message.Contains("Invalid anchor"))
{
    // prompt the user for a corrected A1 range
}

Prevention

When it happens

Trigger: Passing `--prop anchor=100,200` (pixel coordinates) or `--prop anchor=R1C1` or `--prop anchor=B2-F7` (hyphen instead of colon) or an empty/garbage anchor string. Also fires when `ref=` resolves to a non-cell value and is mapped into anchor=.

Common situations: Mixing up the legacy x/y/width/height numeric form with the cell-range anchor form; copying anchor syntax from a different tool (SpreadsheetML, Google Sheets, R1C1); leftover whitespace or a stray quote around the cell reference.

Related errors


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