iOfficeAI/OfficeCLI · error · ArgumentException
Anchor must be a row path like /{targetSheetName}/row[K], go
Error message
Anchor must be a row path like /{targetSheetName}/row[K], got: {anchorPath} What it means
Thrown by the row-anchor resolver when a --before/--after anchor path has no second segment after trimming (aSegs.Length < 2), i.e. the anchor is just a sheet like "/Sheet1" with no '/row[K]'. Row anchors must be full element paths so the handler can locate the sibling row.
Source
Thrown at src/officecli/Handlers/Excel/ExcelHandler.Add.cs:317
var row = (rowIdx >= 1 && rowIdx <= allRows.Count ? allRows[PathIndex.ToArrayIndex(rowIdx)] : null)
?? sheetData.Elements<Row>().FirstOrDefault(r => r.RowIndex?.Value == (uint)rowIdx)
?? throw new ArgumentException($"Row {rowIdx} not found");
// 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;
}View on GitHub (pinned to 1ced45e900)
Solutions
- Provide the full anchor: "/<TargetSheet>/row[K]".
- Build anchors from a verified row path, not a sheet path.
- For a same-sheet move, ensure targetParentPath is null so the anchor sheet defaults correctly.
Example fix
// before
h.Move("/Sheet1/row[3]", null, InsertPosition.AfterElement("/Sheet1")); // no row segment
// after
h.Move("/Sheet1/row[3]", null, InsertPosition.AfterElement("/Sheet1/row[5]")); Defensive patterns
Strategy: validation
Validate before calling
string AssertRowAnchor(string anchor)
{
var segs = anchor.TrimStart('/').Split('/', 2);
if (segs.Length < 2)
throw new ArgumentException($"Row anchor needs a /sheet/row[K] form: '{anchor}'");
return anchor;
}
var after = pos?.After is null ? null : AssertRowAnchor(pos.After);
var before = pos?.Before is null ? null : AssertRowAnchor(pos.Before); Type guard
static bool IsFullElementPath(string p) =>
p.TrimStart('/').Split('/', 2).Length >= 2; Prevention
- Always include the /row[K] suffix on row anchors.
- Build anchors from a verified row path, not a sheet path.
- Reuse a shared validator for both before/after anchors.
When it happens
Trigger: InsertPosition.BeforeElement("/Sheet1") or AfterElement("/Sheet1") for a row move; anchor passed as a bare sheet name; missing '/row[K]' suffix.
Common situations: User reused a sheet-level anchor (valid for whole-sheet reorder) for a row move; truncation when building the anchor path.
Related errors
- Anchor sheet '{aSegs[0]}' must match target sheet '{targetSh
- Anchor row {anchorRowIdx} not found in {targetSheetName}
- Anchor must be a col path like /{sheetName}/col[L], got: {an
- After anchor not found: {position.After}
- Before anchor not found: {position.Before}
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/86a567e8577cb119.
Report an issue: GitHub.