iOfficeAI/OfficeCLI · error · ArgumentException
Before anchor not found: {position.Before}
Error message
Before anchor not found: {position.Before} What it means
Thrown when moving a whole sheet with --before where the anchor sheet named in position.Before is not in the <sheets> catalog. Same guard as the --after case: the handler needs a real sibling to insert before, and an unknown anchor name stops the move.
Source
Thrown at src/officecli/Handlers/Excel/ExcelHandler.Add.cs:206
// Resolve after/before anchor BEFORE removing sheetEl.
static string ExtractAnchorSheetName(string raw) =>
(raw.StartsWith("/") ? raw[1..] : raw).Split('/', 2)[0];
Sheet? afterAnchor = null, beforeAnchor = null;
if (position?.After != null)
{
var anchorName = ExtractAnchorSheetName(position.After);
afterAnchor = sheets.Elements<Sheet>().FirstOrDefault(s =>
string.Equals(s.Name?.Value, anchorName, StringComparison.OrdinalIgnoreCase))
?? throw new ArgumentException($"After anchor not found: {position.After}");
}
else if (position?.Before != null)
{
var anchorName = ExtractAnchorSheetName(position.Before);
beforeAnchor = sheets.Elements<Sheet>().FirstOrDefault(s =>
string.Equals(s.Name?.Value, anchorName, StringComparison.OrdinalIgnoreCase))
?? throw new ArgumentException($"Before anchor not found: {position.Before}");
}
else if (index == null)
{
throw new ArgumentException("One of --index, --after, or --before is required when moving a sheet");
}
// Self-move guard: moving a sheet after/before itself is a no-op.
// Removing first detaches sheetEl, then InsertAfterSelf/InsertBeforeSelf
// throws "parent is null" and the sheet is lost (data loss).
if (ReferenceEquals(afterAnchor, sheetEl) || ReferenceEquals(beforeAnchor, sheetEl))
return $"/{sheetName}";
// localSheetId on <definedName> is a 0-based position into
// <sheets>; capture the pre-move order so scoped names can be
// remapped to the sheets' new positions after the reorder.
var preMoveOrder = sheets.Elements<Sheet>().ToList();
sheetEl.Remove();View on GitHub (pinned to 1ced45e900)
Solutions
- Verify the anchor sheet name against the live <sheets> list before calling Move.
- Fall back to InsertPosition.AtIndex(n) for an absolute target.
- Re-read the path from the current workbook if sheets were edited in another session.
Example fix
// before
h.Move("/Sheet1", null, InsertPosition.BeforeElement("/Finale")); // 'Finale' typo for 'Final'
// after
h.Move("/Sheet1", null, InsertPosition.BeforeElement("/Final")); Defensive patterns
Strategy: validation
Validate before calling
string AnchorSheet(string raw) => (raw.StartsWith("/") ? raw[1..] : raw).Split('/', 2)[0];
var sheets = handler.Get("/", depth: 1).Children.Select(c => c.Name).ToList();
if (pos?.Before is { } b && !sheets.Any(s => s.Equals(AnchorSheet(b), StringComparison.OrdinalIgnoreCase)))
throw new InvalidOperationException($"--before anchor sheet '{b}' does not exist"); Try / catch
try { handler.Move("/Sheet1", null, InsertPosition.BeforeElement(anchor)); }
catch (ArgumentException ex) when (ex.Message.StartsWith("Before anchor not found"))
{ /* list sheets and let the user pick a valid before-anchor */ } Prevention
- Confirm the before-anchor sheet exists in the live <sheets> list.
- Re-read anchor names after any sheet rename/delete.
- Use AtIndex(n) to avoid anchor lookups entirely.
When it happens
Trigger: Move("/Sheet1", null, InsertPosition.BeforeElement("/Missing")) where 'Missing' is absent; misspelled anchor; anchor sheet removed after the path was built.
Common situations: Stale anchor path; renamed target sheet; referring to a hidden/very-hidden sheet name that differs from the catalog entry.
Related errors
- After anchor not found: {position.After}
- Anchor row {anchorRowIdx} not found in {targetSheetName}
- One of --index, --after, or --before is required when moving
- Target sheet not found: {tgtSegments[0]}
- Row {rowIdx} not found
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/13a506d9beab3d4b.
Report an issue: GitHub.