iOfficeAI/OfficeCLI · error · ArgumentException

Anchor sheet ' ' must match target sheet

Error message

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

What it means

Thrown by the row-anchor resolver when the anchor's sheet segment does not match the target sheet (aSegs[0] != targetSheetName, case-insensitive). Cross-sheet row anchors are rejected: the anchor row must live in the same sheet the row is being moved into, otherwise the resolved position would be meaningless.

Solutions

  1. Make the anchor's sheet equal the target sheet (or omit targetParentPath for a same-sheet move and anchor within the source sheet).
  2. Derive targetSheetName from targetParentPath and build the anchor from it.
  3. Use InsertPosition.AtIndex(n) to avoid anchor-sheet coupling entirely.

Example fix

// before
h.Move("/Src/row[1]", "/Dst", InsertPosition.AfterElement("/Src/row[2]")); // anchor sheet != target
// after
h.Move("/Src/row[1]", "/Dst", InsertPosition.AfterElement("/Dst/row[2]"));
Defensive patterns

Strategy: validation

Validate before calling

string targetSheet = string.IsNullOrEmpty(targetParentPath)
    ? sourcePath.TrimStart('/').Split('/', 2)[0]
    : targetParentPath.TrimStart('/').Split('/', 2)[0];
foreach (var anchor in new[] { pos?.After, pos?.Before }.Where(a => a != null)!)
{
    var aSheet = anchor.TrimStart('/').Split('/', 2)[0];
    if (!aSheet.Equals(targetSheet, StringComparison.OrdinalIgnoreCase))
        throw new InvalidOperationException($"Anchor sheet '{aSheet}' must equal target '{targetSheet}'");
}

Prevention

When it happens

Trigger: Moving into Sheet2 but passing InsertPosition.AfterElement("/Sheet1/row[2]"); targetParentPath names a different sheet than the anchor; anchor copied from the source sheet while moving cross-sheet.

Common situations: Cross-sheet move where the user kept the source sheet in the anchor; refactoring a same-sheet call to cross-sheet without updating the anchor.

Related errors


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

Appendix: source

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

            // Resolve --before / --after anchors to a 0-based document-order
            // position in the target sheet. Anchor must be /<TargetSheet>/row[K].
            // Resolved BEFORE removing the moved row so the anchor is found by
            // its current position.
            int? targetIndex = index;
            string targetSheetName = string.IsNullOrEmpty(targetParentPath)
                ? sheetName
                : targetParentPath.TrimStart('/').Split('/', 2)[0];
            if (targetIndex == null && position != null && (position.After != null || position.Before != null))
            {
                int FindAnchorRowPos(string anchorPath)
                {
                    var aSegs = anchorPath.TrimStart('/').Split('/', 2);
                    if (aSegs.Length < 2)
                        throw new ArgumentException(
                            $"Anchor must be a row path like /{targetSheetName}/row[K], got: {anchorPath}");
                    if (!aSegs[0].Equals(targetSheetName, StringComparison.OrdinalIgnoreCase))
                        throw new ArgumentException(
                            $"Anchor sheet '{aSegs[0]}' must match target sheet '{targetSheetName}'");
                    var am = Regex.Match(aSegs[1], @"^row\[(\d+)\]$");
                    if (!am.Success)
                        throw new ArgumentException(
                            $"Anchor must be a row path like /{targetSheetName}/row[K], got: {anchorPath}");
                    var anchorRowIdx = uint.Parse(am.Groups[1].Value);
                    var pos = targetSheetData.Elements<Row>().ToList()
                        .FindIndex(r => r.RowIndex?.Value == anchorRowIdx);
                    if (pos < 0)
                        throw new ArgumentException($"Anchor row {anchorRowIdx} not found in {targetSheetName}");
                    return pos;
                }
                if (position.Before != null) targetIndex = FindAnchorRowPos(position.Before);
                else targetIndex = FindAnchorRowPos(position.After!) + 1;
            }

            // If the moved row sits before the anchor in the same sheet,
            // removing it shifts everything (including the anchor) up by one.

View on GitHub (pinned to 1ced45e900)