{"record":{"id":"2b1a23d55de435a7","repo":"iOfficeAI/OfficeCLI","slug":"unrecognized-cell-parent-path-segment-cellsegmen","errorCode":null,"errorMessage":"Unrecognized cell parent path segment '{cellSegments[1]}'. Expected a cell reference (e.g. A2), cell[A2], or row[N].","messagePattern":"Unrecognized cell parent path segment '(.+?)'\\. Expected a cell reference \\(e\\.g\\. A2\\), cell\\[A2\\], or row\\[N\\]\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs","lineNumber":380,"sourceCode":"        {\n            var rowPathMatch = Regex.Match(cellSegments[1], @\"^row\\[(\\d+)\\]$\", RegexOptions.IgnoreCase);\n            if (rowPathMatch.Success)\n                rowIndexFromPath = uint.Parse(rowPathMatch.Groups[1].Value);\n        }\n\n        // BUG-R2: an unrecognized parent path tail (e.g. r[2], foo[2], xyz[5])\n        // matched none of the three accepted forms above (bare cell-ref,\n        // cell[<ref>], row[N]), leaving both cellRefFromPath and rowIndexFromPath\n        // null. The auto-assign branch below then silently snapped to row 1,\n        // misplacing data without warning. Reject it instead. (Bare /Sheet1 with\n        // cellSegments.Length == 1 is unaffected — that's a legitimate\n        // auto-append target.) No r[N] alias is added: Get/Query don't support\n        // r[N], so accepting it on Add would break Add/Get symmetry.\n        if (cellSegments.Length > 1\n            && cellRefFromPath == null\n            && rowIndexFromPath == null)\n        {\n            throw new ArgumentException(\n                $\"Unrecognized cell parent path segment '{cellSegments[1]}'. \" +\n                $\"Expected a cell reference (e.g. A2), cell[A2], or row[N].\");\n        }\n\n        string cellRef;\n        // BUG-R36-B1: when --prop arrayformula= is supplied with --prop ref=A1:C3,\n        // the range is the spill region, not a single cell address. Detect it and\n        // resolve cellRef to the top-left so FindOrCreateCell doesn't reject the\n        // colon. The full range is still passed through to arrayformula below via\n        // properties[\"ref\"].\n        string? arrayFormulaRefRange = null;\n        if (properties.ContainsKey(\"ref\"))\n        {\n            cellRef = properties[\"ref\"];\n            if (cellRef.Contains(':') && properties.ContainsKey(\"arrayformula\"))\n            {\n                arrayFormulaRefRange = cellRef;\n                var topLeft = cellRef.Split(':', 2)[0];","sourceCodeStart":362,"sourceCodeEnd":398,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs#L362-L398","documentation":"AddCell's parent path may carry a tail segment that is a bare cell-ref (e.g. A2), cell[<ref>] (e.g. cell[A2]), or row[N] (e.g. row[5]). Any other tail shape (r[2], foo[2], xyz[5]) matches none of the three accepted forms, leaves both the cell-ref and row-index unresolved, and previously caused a silent snap to row 1. This guard rejects it explicitly so data is not mislaced without warning. A bare /Sheet1 (no tail) is unaffected — that is a legitimate auto-append target.","triggerScenarios":"Add(\"/Sheet1/r[2]\",\"cell\",...); parentPath tail like \"foo[5]\", \"xyz[2]\", \"cell5\", or \"row\" (no brackets); any bracketed form whose prefix is not cell/row and whose content is not a bare A1 ref.","commonSituations":"Confusing row[N] with an r[N] alias (Get/Query do not support r[N], so Add does not either to keep symmetry); copy-pasting a path from another element type; templating code that builds the tail from a variable that produced an unexpected shape.","solutions":["Use one of the three accepted tail forms: a bare cell reference (/Sheet1/A2), cell[<ref>] (/Sheet1/cell[A2]), or row[N] (/Sheet1/row[5]).","If you want auto-append within a specific row, use /Sheet1/row[N] and let AddCell pick the next free column.","For a bare sheet auto-append target, omit the tail entirely: /Sheet1."],"exampleFix":"// before\nhandler.Add(\"/Sheet1/r[2]\", \"cell\", null, new() { [\"value\"] = \"x\" });\n// after\nhandler.Add(\"/Sheet1/row[2]\", \"cell\", null, new() { [\"value\"] = \"x\" });","handlingStrategy":"validation","validationCode":"static bool IsValidCellParentTail(string path)\n{\n    var seg = path.TrimStart('/').Split('/', 2);\n    if (seg.Length == 1) return true; // bare sheet = auto-append\n    var t = seg[1];\n    return Regex.IsMatch(t, @\"^[A-Z]+\\d+$\", RegexOptions.IgnoreCase)\n        || Regex.IsMatch(t, @\"^cell\\[[A-Z]+\\d+\\]$\", RegexOptions.IgnoreCase)\n        || Regex.IsMatch(t, @\"^row\\[\\d+]$\", RegexOptions.IgnoreCase);\n}\nif (!IsValidCellParentTail(parentPath)) throw new ArgumentException(\"Bad cell parent tail.\");","typeGuard":"static bool IsAcceptedCellTail(string t) =>\n    Regex.IsMatch(t, @\"^[A-Z]+\\d+$\", RegexOptions.IgnoreCase)\n    || Regex.IsMatch(t, @\"^cell\\[[A-Z]+\\d+\\]$\", RegexOptions.IgnoreCase)\n    || Regex.IsMatch(t, @\"^row\\[\\d+]$\", RegexOptions.IgnoreCase);","tryCatchPattern":"try { h.Add(parentPath, \"cell\", pos, props); }\ncatch (ArgumentException ex) when (ex.Message.StartsWith(\"Unrecognized cell parent path segment\"))\n{ /* rewrite the tail to an accepted form */ }","preventionTips":["Do not invent aliases like r[N] — Get/Query do not support them either.","When building paths dynamically, validate the tail against the three accepted forms.","Prefer the bare cell-ref form (/Sheet1/A2) for clarity."],"tags":["excel","xlsx","cell","path","validation"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}