iOfficeAI/OfficeCLI · error · ArgumentException

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

Error message

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

What it means

Thrown when the OLE 'anchor' property fails to match the expected cell or cell-range pattern. The OLE anchor parser uses its own inline regex ^([A-Z]+)(\d+)(?::([A-Z]+)(\d+))?$ (case-insensitive) rather than the shared TryParseCellRangeAnchor. A width/height warning is emitted first (those are ignored with anchor=), then the anchor format error fires if parsing fails.

Source

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

        int oleFromCol, oleFromRow, oleToCol, oleToRow;
        // FromMarker offsets are always zero (anchor starts at cell boundary);
        // ToMarker offsets carry the sub-cell EMU remainder for unit-qualified
        // width/height inputs, preserving round-trip precision.
        const long oleFromColOff = 0, oleFromRowOff = 0;
        long oleToColOff = 0, oleToRowOff = 0;
        if (properties.TryGetValue("anchor", out var oleAnchorStr) && !string.IsNullOrWhiteSpace(oleAnchorStr))
        {
            // CONSISTENCY(ole-width-units): anchor= defines the full
            // rectangle (start+end cells), so width/height on the same
            // Add call would be ambiguous and are silently dropped.
            // Warn loudly rather than fail, so existing scripts keep
            // working but users notice the dropped value.
            if (properties.ContainsKey("width") | properties.ContainsKey("height"))
                Console.Error.WriteLine(
                    "Warning: 'width'/'height' are ignored when 'anchor' is provided (anchor defines the full rectangle).");
            var m = Regex.Match(oleAnchorStr, @"^([A-Z]+)(\d+)(?::([A-Z]+)(\d+))?$", RegexOptions.IgnoreCase);
            if (!m.Success)
                throw new ArgumentException($"Invalid anchor: '{oleAnchorStr}'. Expected e.g. 'B2' or 'B2:E6'.");
            // CONSISTENCY(xdr-coords): XDR ColumnId/RowId are 0-based;
            // ColumnNameToIndex returns 1-based, so subtract 1 here.
            oleFromCol = ColumnNameToIndex(m.Groups[1].Value) - 1;
            oleFromRow = int.Parse(m.Groups[2].Value) - 1;
            ValidateAnchorCell(oleFromCol, oleFromRow, oleAnchorStr.Split(':')[0]);
            if (m.Groups[3].Success)
            {
                oleToCol = ColumnNameToIndex(m.Groups[3].Value) - 1;
                oleToRow = int.Parse(m.Groups[4].Value) - 1;
                ValidateAnchorCell(oleToCol, oleToRow, oleAnchorStr.Split(':')[1]);
                NormalizeAnchorRect(ref oleFromCol, ref oleFromRow, ref oleToCol, ref oleToRow);
            }
            else
            {
                oleToCol = oleFromCol + 2;
                oleToRow = oleFromRow + 3;
            }
        }

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Use 'B2' for a single-cell anchor or 'B2:E6' for a range.
  2. Use colon (:) not comma (,) for the range separator.
  3. If you need numeric positioning, drop anchor= and use x=/y=/width=/height= instead.
  4. Ensure column letters are valid (A-XFD) and rows are 1-1048576.

Example fix

// before
add /Sheet1 --type ole --src obj.xlsx --anchor "B2,E6"
// after
add /Sheet1 --type ole --src obj.xlsx --anchor "B2:E6"
Defensive patterns

Strategy: validation

Validate before calling

// Validate OLE anchor format before the add call
if (properties.TryGetValue("anchor", out var oleAnchor) && !string.IsNullOrWhiteSpace(oleAnchor))
{
    if (!System.Text.RegularExpressions.Regex.IsMatch(
            oleAnchor, @"^[A-Z]+\d+(:[A-Z]+\d+)?$", RegexOptions.IgnoreCase))
        throw new InvalidOperationException(
            $"Invalid OLE anchor '{oleAnchor}'. Expected 'B2' or 'B2:E6'.");
}

Type guard

static bool IsValidOleAnchor(string? s) =>
    !string.IsNullOrWhiteSpace(s) &&
    System.Text.RegularExpressions.Regex.IsMatch(
        s, @"^[A-Z]+\d+(:[A-Z]+\d+)?$", RegexOptions.IgnoreCase);

Try / catch

try { handler.AddOle(parentPath, properties); }
catch (ArgumentException ex) when (ex.Message.StartsWith("Invalid anchor:"))
{
    Console.Error.WriteLine($"{ex.Message} Use 'B2' or 'B2:E6' format.");
}

Prevention

When it happens

Trigger: Setting properties["anchor"] to anything not matching ColRow or ColRow:ColRow, e.g. 'B-2', 'row5col2', 'B2,E6', 'B2:'. Also fires if ValidateAnchorCell rejects a cell outside the grid (A0, XFE1).

Common situations: User copies pixel-based or R1C1 coordinates. User uses a comma instead of a colon for ranges. Copy-paste introduces invisible characters.

Related errors


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