{"record":{"id":"c425f58535457c3b","repo":"iOfficeAI/OfficeCLI","slug":"anchor-must-be-a-column-path-like-colsheetname","errorCode":null,"errorMessage":"Anchor must be a column path like /{colSheetName}/col[L], got: {anchorPath}","messagePattern":"Anchor must be a column path like /(.+?)/col\\[L\\], got: (.+?)","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs","lineNumber":1047,"sourceCode":"\n    private string AddCol(string parentPath, string type, InsertPosition? position, Dictionary<string, string> properties)\n    {\n        var colSegments = parentPath.TrimStart('/').Split('/', 2);\n        var colSheetName = colSegments[0];\n        var colWorksheet = FindWorksheet(colSheetName)\n            ?? throw new ArgumentException($\"Sheet not found: {colSheetName}\");\n\n        // Resolve --before / --after anchors, mirroring AddRow. Anchor must\n        // be /<sheetName>/col[L] in the same sheet; --before takes the\n        // anchor's slot, --after lands one column to the right.\n        int? index = position?.Index;\n        if (index == null && position != null && (position.After != null || position.Before != null))\n        {\n            int FindAnchorColIndex(string anchorPath)\n            {\n                var aSegs = anchorPath.TrimStart('/').Split('/', 2);\n                if (aSegs.Length < 2)\n                    throw new ArgumentException(\n                        $\"Anchor must be a column path like /{colSheetName}/col[L], got: {anchorPath}\");\n                if (!aSegs[0].Equals(colSheetName, StringComparison.OrdinalIgnoreCase))\n                    throw new ArgumentException(\n                        $\"Anchor sheet '{aSegs[0]}' must match target sheet '{colSheetName}'\");\n                var am = Regex.Match(aSegs[1], @\"^col\\[([A-Za-z]+)\\]$\", RegexOptions.IgnoreCase);\n                if (!am.Success)\n                    throw new ArgumentException(\n                        $\"Anchor must be a column path like /{colSheetName}/col[L], got: {anchorPath}\");\n                return ColumnNameToIndex(am.Groups[1].Value.ToUpperInvariant());\n            }\n            if (position.Before != null) index = FindAnchorColIndex(position.Before);\n            else index = FindAnchorColIndex(position.After!) + 1;\n        }\n\n        // Determine insert column: index (1-based) or name/letter from properties\n        // CONSISTENCY(col-letter-prop): accept col=, letter=, column= as aliases of name=\n        // matching how `colbreak` (case \"colbreak\" above) accepts col/column/index.\n        string insertColName;","sourceCodeStart":1029,"sourceCodeEnd":1065,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs#L1029-L1065","documentation":"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.","triggerScenarios":"Add(\"/Sheet1\",\"col\",InsertPosition.BeforeElement(\"/Sheet1\"),props) — anchor path is bare sheet, no col[L] tail; InsertPosition.AfterElement(\"/Sheet1\") with the same shape.","commonSituations":"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.","solutions":["Supply a full column anchor path: /<sheetName>/col[L], e.g. /Sheet1/col[C].","If you want to append rather than anchor, omit --before/--after and pass position=null (or use name=/col= to place the column).","Use InsertPosition.AtIndex or the name=/col= property for positional control instead of an anchor when you do not have a reference column."],"exampleFix":"// before\nhandler.Add(\"/Sheet1\", \"col\", InsertPosition.BeforeElement(\"/Sheet1\"), new());\n// after\nhandler.Add(\"/Sheet1\", \"col\", InsertPosition.BeforeElement(\"/Sheet1/col[C]\"), new());","handlingStrategy":"validation","validationCode":"static bool IsValidColAnchor(string anchor)\n{\n    var seg = anchor.TrimStart('/').Split('/', 2);\n    return seg.Length >= 2;\n}\nif (pos?.Before != null && !IsValidColAnchor(pos.Before)) throw new ArgumentException(\"anchor needs a col[L] tail\");\nif (pos?.After  != null && !IsValidColAnchor(pos.After))  throw new ArgumentException(\"anchor needs a col[L] tail\");","typeGuard":"static bool HasColTail(string anchor) =>\n    anchor.TrimStart('/').Split('/', 2).Length >= 2;","tryCatchPattern":"try { h.Add(colPath, \"col\", pos, props); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"Anchor must be a column path\"))\n{ /* append /col[L] to the anchor path and retry */ }","preventionTips":["Always pass the full /<sheet>/col[L] form as an anchor.","Do not reuse the bare parent path as the --before/--after target.","Use AtIndex or name=/col= for positional control when you have no reference column."],"tags":["excel","xlsx","col","anchor","path","validation"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}