iOfficeAI/OfficeCLI · error · System.ArgumentException

Anchor sheet '{aSegs[0]}' must match target sheet '{colSheet

Error message

Anchor sheet '{aSegs[0]}' must match target sheet '{colSheetName}'

What it means

Thrown by AddCol when resolving a --before/--after anchor for a column insertion. The anchor path's sheet segment (aSegs[0]) does not match the target sheet name (colSheetName) that the column is being added to. The comparison is OrdinalIgnoreCase, so it is purely a name mismatch, not a casing issue. This guard prevents inserting into one sheet using an anchor that lives in a different sheet, which would silently produce a wrong column index.

Source

Thrown at src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs:1050

        var colSegments = parentPath.TrimStart('/').Split('/', 2);
        var colSheetName = colSegments[0];
        var colWorksheet = FindWorksheet(colSheetName)
            ?? throw new ArgumentException($"Sheet not found: {colSheetName}");

        // Resolve --before / --after anchors, mirroring AddRow. Anchor must
        // be /<sheetName>/col[L] in the same sheet; --before takes the
        // anchor's slot, --after lands one column to the right.
        int? index = position?.Index;
        if (index == null && position != null && (position.After != null || position.Before != null))
        {
            int FindAnchorColIndex(string anchorPath)
            {
                var aSegs = anchorPath.TrimStart('/').Split('/', 2);
                if (aSegs.Length < 2)
                    throw new ArgumentException(
                        $"Anchor must be a column path like /{colSheetName}/col[L], got: {anchorPath}");
                if (!aSegs[0].Equals(colSheetName, StringComparison.OrdinalIgnoreCase))
                    throw new ArgumentException(
                        $"Anchor sheet '{aSegs[0]}' must match target sheet '{colSheetName}'");
                var am = Regex.Match(aSegs[1], @"^col\[([A-Za-z]+)\]$", RegexOptions.IgnoreCase);
                if (!am.Success)
                    throw new ArgumentException(
                        $"Anchor must be a column path like /{colSheetName}/col[L], got: {anchorPath}");
                return ColumnNameToIndex(am.Groups[1].Value.ToUpperInvariant());
            }
            if (position.Before != null) index = FindAnchorColIndex(position.Before);
            else index = FindAnchorColIndex(position.After!) + 1;
        }

        // Determine insert column: index (1-based) or name/letter from properties
        // CONSISTENCY(col-letter-prop): accept col=, letter=, column= as aliases of name=
        // matching how `colbreak` (case "colbreak" above) accepts col/column/index.
        string insertColName;
        string? colLetterProp = null;
        if (properties.TryGetValue("name", out var colNameProp) && !string.IsNullOrEmpty(colNameProp))
            colLetterProp = colNameProp;

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Make the anchor path's sheet segment identical to the target sheet: use /<colSheetName>/col[L] for both --before and --after.
  2. If you intend to anchor relative to a column in another sheet, insert the column there instead, or compute the absolute numeric index and pass it via position.Index to bypass anchor resolution entirely.
  3. Verify the sheet name spelling against the workbook with a Get on /SheetName before constructing the position.

Example fix

// before
var pos = new InsertPosition { Before = "/Sheet2/col[B]" };
handler.Add("/Sheet1", "col", pos, props);

// after
var pos = new InsertPosition { Before = "/Sheet1/col[B]" };
handler.Add("/Sheet1", "col", pos, props);
Defensive patterns

Strategy: validation

Validate before calling

string targetSheet = "Sheet1";
string anchor = "/Sheet1/col[B]";
var aSegs = anchor.TrimStart('/').Split('/', 2);
if (aSegs.Length < 2 || !aSegs[0].Equals(targetSheet, StringComparison.OrdinalIgnoreCase))
    throw new InvalidOperationException($"Anchor sheet must be {targetSheet}");
handler.Add("/" + targetSheet, "col", new InsertPosition { Before = anchor }, props);

Type guard

static bool AnchorTargetsSheet(string anchorPath, string targetSheet)
{
    var segs = anchorPath.TrimStart('/').Split('/', 2);
    return segs.Length >= 2
        && segs[0].Equals(targetSheet, StringComparison.OrdinalIgnoreCase)
        && System.Text.RegularExpressions.Regex.IsMatch(segs[1], @"^col\[([A-Za-z]+)\]$", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
}

Prevention

When it happens

Trigger: Calling Add with type=col on /TargetSheet and an InsertPosition whose Before or After is a path like /OtherSheet/col[C] where OtherSheet != TargetSheet. For example: parentPath="/Sheet1", position.Before="/Sheet2/col[B". The local function FindAnchorColIndex is only invoked when position.Index is null and Before/After is set.

Common situations: Script copies an anchor path from a different sheet's dump output and reuses it verbatim. Renaming a sheet after copying anchor paths. Mixing up sheet variables when building the position object across two sheets in the same script.

Related errors


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