{"record":{"id":"334be2e78d632c70","repo":"iOfficeAI/OfficeCLI","slug":"invalid-merge-ref-newrangeref-must-be-a-singl","errorCode":null,"errorMessage":"Invalid merge ref '{newRangeRef}': must be a single A1 cell (e.g. 'B2') or A1:B2 range (e.g. 'B4:E4').","messagePattern":"Invalid merge ref '(.+?)': must be a single A1 cell \\(e\\.g\\. 'B2'\\) or A1:B2 range \\(e\\.g\\. 'B4:E4'\\)\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Helpers.Validation.cs","lineNumber":470,"sourceCode":"    //   with prior dedup behavior).\n    // - Geometric overlap with a non-identical range: throw.\n    // - Otherwise: append.\n    private static readonly System.Text.RegularExpressions.Regex SingleMergeRefPattern =\n        new(@\"^[A-Z]+[0-9]+(:[A-Z]+[0-9]+)?$\",\n            System.Text.RegularExpressions.RegexOptions.Compiled);\n\n    // CONSISTENCY(merge-comma): callers should run this BEFORE creating an\n    // empty <mergeCells> container, so a rejected ref doesn't leave a\n    // schema-invalid empty container in the saved file.\n    private static void ValidateMergeRefLiteral(string newRangeRef)\n    {\n        var refUpper = newRangeRef.ToUpperInvariant();\n        if (refUpper.Contains(','))\n            throw new ArgumentException(\n                $\"Invalid merge ref '{newRangeRef}': path is a single-target locator (no comma). \" +\n                $\"Move ranges to a prop value, e.g. `set ... '/Sheet1' --prop merge={newRangeRef}`.\");\n        if (!SingleMergeRefPattern.IsMatch(refUpper))\n            throw new ArgumentException(\n                $\"Invalid merge ref '{newRangeRef}': must be a single A1 cell (e.g. 'B2') or A1:B2 range (e.g. 'B4:E4').\");\n        // CONSISTENCY(merge-orientation): the ref must read top-left to\n        // bottom-right. Z1:A1 / A10:A1 / B2:A1 (any reversed orientation)\n        // were silently accepted; Excel itself only writes the canonical\n        // form, so callers passing a reversed pair almost certainly typo'd.\n        // Reject with a hint to swap, mirroring the orientation guard the\n        // sheetShift normalizer applies after the fact (ExcelHandler.Set.cs\n        // L1918) and matching how other range-bearing props (validation,\n        // table, autofilter) demand canonical orientation up front.\n        var colonIdx = refUpper.IndexOf(':');\n        if (colonIdx > 0)\n        {\n            var lhs = refUpper.Substring(0, colonIdx);\n            var rhs = refUpper.Substring(colonIdx + 1);\n            try\n            {\n                var (lCol, lRow) = ParseCellReference(lhs);\n                var (rCol, rRow) = ParseCellReference(rhs);","sourceCodeStart":452,"sourceCodeEnd":488,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Helpers.Validation.cs#L452-L488","documentation":"The merge-cell ref does not match the single-cell (B2) or canonical range (B4:E4) A1 pattern enforced by SingleMergeRefPattern: ^[A-Z]+[0-9]+(:[A-Z]+[0-9]+)?$. The ref is upper-cased first, so case is not the issue; shape is.","triggerScenarios":"Passing a merge ref like 'A1:B2:C3' (three tokens), 'B' (no row), '2' (no column), 'A1 to B2' (words), 'top-left', or any non-A1 string. The regex fails and the guard throws.","commonSituations":"Free-text UI input; wrong delimiter ('..' or 'to' instead of ':'); localized decimal separators; copy-paste from a non-Excel source.","solutions":["Use strict A1 notation: a single cell 'B2' or a colon range 'B4:E4'.","Build the ref from numeric indices via the library's IndexToColumnName helper to avoid typos.","Strip non-ASCII or localized separators before validation."],"exampleFix":"// before\nsheet.Merge(\"A1 .. B2\");\n\n// after\nsheet.Merge(\"A1:B2\");","handlingStrategy":"validation","validationCode":"static readonly Regex MergeRefShape = new(@\"^[A-Z]+[0-9]+(:[A-Z]+[0-9]+)?$\");\nstatic bool IsValidMergeRef(string r) =>\n    MergeRefShape.IsMatch((r ?? string.Empty).ToUpperInvariant());","typeGuard":null,"tryCatchPattern":"try { sheet.Merge(refText); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"single A1 cell\")) {\n    // re-prompt the user / re-derive the ref\n}","preventionTips":["Construct merge refs from cell indices, not free text.","Validate ref shape before calling Merge."],"tags":["excel","merge","cell-reference","validation"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}