{"record":{"id":"6ad02901cfcb5bb3","repo":"iOfficeAI/OfficeCLI","slug":"invalid-merge-ref-newrangeref-path-is-a-singl","errorCode":null,"errorMessage":"Invalid merge ref '{newRangeRef}': path is a single-target locator (no comma). Move ranges to a prop value, e.g. `set ... '/Sheet1' --prop merge={newRangeRef}`.","messagePattern":"Invalid merge ref '(.+?)': path is a single-target locator \\(no comma\\)\\. Move ranges to a prop value, e\\.g\\. `set \\.\\.\\. '/Sheet1' --prop merge=(.+?)`\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Handlers/Excel/ExcelHandler.Helpers.Validation.cs","lineNumber":466,"sourceCode":"    // \"found a problem\" repair dialog, but the OOXML SDK happily\n    // appends them. Mirrors the T4 overlap-throws pattern used by\n    // tables and AutoFilter+table.\n    // - Exact-match ref: no-op (idempotent re-Add stays consistent\n    //   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);","sourceCodeStart":448,"sourceCodeEnd":484,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Handlers/Excel/ExcelHandler.Helpers.Validation.cs#L448-L484","documentation":"A merge-cell ref passed as a path target contained a comma, which denotes a multi-target locator. Merge operations accept a single A1 cell or A1:B2 range per target; comma-separated lists belong in a prop value, not the path. The library rejects commas before any further parsing.","triggerScenarios":"Calling a set/merge API with a path target like '/Sheet1/A1:B2,C3:D4' — the comma trips ValidateMergeRefLiteral immediately.","commonSituations":"Trying to merge several ranges in one CLI invocation; passing a range list where a single target is expected; misreading the path grammar.","solutions":["Move the comma-separated ranges into the --prop merge value as the message suggests.","Issue one merge call per range instead of packing them into the path.","Check the CLI's path-vs-prop distinction in the docs before batching."],"exampleFix":"# before\nofficecli set /Sheet1/A1:B2,C3:D4 --prop merge=true\n\n# after\nofficecli set /Sheet1 --prop merge=A1:B2,C3:D4","handlingStrategy":"validation","validationCode":"static string SingleMergeTarget(string path) {\n    if (path.Contains(','))\n        throw new InvalidOperationException(\"Pass comma-separated merge ranges via --prop merge=...\");\n    return path;\n}","typeGuard":null,"tryCatchPattern":"try { cli.Set($\"/Sheet1/{target}\", merge: true); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"no comma\")) {\n    cli.Set(\"/Sheet1\", prop: $\"merge={target}\");\n}","preventionTips":["Keep the path/target vs prop-value distinction explicit in your CLI wrappers.","Batch merge ranges through the prop channel, not the path."],"tags":["excel","merge","cell-reference","cli"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}