iOfficeAI/OfficeCLI · error · ArgumentException

Anchor must be a column path like /{colSheetName}/col[L], go

Error message

Anchor must be a column path like /{colSheetName}/col[L], got: {anchorPath}

What it means

AddCol's anchor resolver (for --before/--after) expects /<sheetName>/col[L]. The local FindAnchorColIndex splits the anchor path on '/'; if there is no second segment (aSegs.Length < 2, e.g. a bare sheet name with no column tail), it throws this message. This rejects an anchor that has no column specifier before it can be misresolved.

Source

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

    private string AddCol(string parentPath, string type, InsertPosition? position, Dictionary<string, string> properties)
    {
        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;

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Supply a full column anchor path: /<sheetName>/col[L], e.g. /Sheet1/col[C].
  2. If you want to append rather than anchor, omit --before/--after and pass position=null (or use name=/col= to place the column).
  3. Use InsertPosition.AtIndex or the name=/col= property for positional control instead of an anchor when you do not have a reference column.

Example fix

// before
handler.Add("/Sheet1", "col", InsertPosition.BeforeElement("/Sheet1"), new());
// after
handler.Add("/Sheet1", "col", InsertPosition.BeforeElement("/Sheet1/col[C]"), new());
Defensive patterns

Strategy: validation

Validate before calling

static bool IsValidColAnchor(string anchor)
{
    var seg = anchor.TrimStart('/').Split('/', 2);
    return seg.Length >= 2;
}
if (pos?.Before != null && !IsValidColAnchor(pos.Before)) throw new ArgumentException("anchor needs a col[L] tail");
if (pos?.After  != null && !IsValidColAnchor(pos.After))  throw new ArgumentException("anchor needs a col[L] tail");

Type guard

static bool HasColTail(string anchor) =>
    anchor.TrimStart('/').Split('/', 2).Length >= 2;

Try / catch

try { h.Add(colPath, "col", pos, props); }
catch (ArgumentException ex) when (ex.Message.Contains("Anchor must be a column path"))
{ /* append /col[L] to the anchor path and retry */ }

Prevention

When it happens

Trigger: Add("/Sheet1","col",InsertPosition.BeforeElement("/Sheet1"),props) — anchor path is bare sheet, no col[L] tail; InsertPosition.AfterElement("/Sheet1") with the same shape.

Common situations: Passing the parent path as the anchor by mistake; building the anchor string from variables where the column letter was empty; confusing the --before target with the parent path.

Related errors


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