iOfficeAI/OfficeCLI · error · ArgumentException

Invalid merge ref '{newRangeRef}': must be a single A1 cell

Error message

Invalid merge ref '{newRangeRef}': must be a single A1 cell (e.g. 'B2') or A1:B2 range (e.g. 'B4:E4').

What it means

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.

Source

Thrown at src/officecli/Handlers/Excel/ExcelHandler.Helpers.Validation.cs:470

    //   with prior dedup behavior).
    // - Geometric overlap with a non-identical range: throw.
    // - Otherwise: append.
    private static readonly System.Text.RegularExpressions.Regex SingleMergeRefPattern =
        new(@"^[A-Z]+[0-9]+(:[A-Z]+[0-9]+)?$",
            System.Text.RegularExpressions.RegexOptions.Compiled);

    // CONSISTENCY(merge-comma): callers should run this BEFORE creating an
    // empty <mergeCells> container, so a rejected ref doesn't leave a
    // schema-invalid empty container in the saved file.
    private static void ValidateMergeRefLiteral(string newRangeRef)
    {
        var refUpper = newRangeRef.ToUpperInvariant();
        if (refUpper.Contains(','))
            throw new ArgumentException(
                $"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}`.");
        if (!SingleMergeRefPattern.IsMatch(refUpper))
            throw new ArgumentException(
                $"Invalid merge ref '{newRangeRef}': must be a single A1 cell (e.g. 'B2') or A1:B2 range (e.g. 'B4:E4').");
        // CONSISTENCY(merge-orientation): the ref must read top-left to
        // bottom-right. Z1:A1 / A10:A1 / B2:A1 (any reversed orientation)
        // were silently accepted; Excel itself only writes the canonical
        // form, so callers passing a reversed pair almost certainly typo'd.
        // Reject with a hint to swap, mirroring the orientation guard the
        // sheetShift normalizer applies after the fact (ExcelHandler.Set.cs
        // L1918) and matching how other range-bearing props (validation,
        // table, autofilter) demand canonical orientation up front.
        var colonIdx = refUpper.IndexOf(':');
        if (colonIdx > 0)
        {
            var lhs = refUpper.Substring(0, colonIdx);
            var rhs = refUpper.Substring(colonIdx + 1);
            try
            {
                var (lCol, lRow) = ParseCellReference(lhs);
                var (rCol, rRow) = ParseCellReference(rhs);

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Use strict A1 notation: a single cell 'B2' or a colon range 'B4:E4'.
  2. Build the ref from numeric indices via the library's IndexToColumnName helper to avoid typos.
  3. Strip non-ASCII or localized separators before validation.

Example fix

// before
sheet.Merge("A1 .. B2");

// after
sheet.Merge("A1:B2");
Defensive patterns

Strategy: validation

Validate before calling

static readonly Regex MergeRefShape = new(@"^[A-Z]+[0-9]+(:[A-Z]+[0-9]+)?$");
static bool IsValidMergeRef(string r) =>
    MergeRefShape.IsMatch((r ?? string.Empty).ToUpperInvariant());

Try / catch

try { sheet.Merge(refText); }
catch (ArgumentException ex) when (ex.Message.Contains("single A1 cell")) {
    // re-prompt the user / re-derive the ref
}

Prevention

When it happens

Trigger: 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.

Common situations: Free-text UI input; wrong delimiter ('..' or 'to' instead of ':'); localized decimal separators; copy-paste from a non-Excel source.

Related errors


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