iOfficeAI/OfficeCLI · error · ArgumentException

Cell reference '{cellRef.Replace("\n", "\\n").Replace("\r",

Error message

Cell reference '{cellRef.Replace("\n", "\\n").Replace("\r", "\\r")}' contains invalid control characters. Expected a clean cell address like 'A1' or 'B2'.

What it means

Thrown when the cell-reference segment (the part after the sheet, e.g. A1 in /Sheet1/A1) contains ASCII control characters (except tab) or DEL (0x7F). The guard exists because .NET regex '$' anchors before a trailing \n, so a value like 'A1\n' would otherwise pass the cell-ref check and silently resolve to a non-existent 'ghost' cell (BUG-R41-F2). Rejecting it surfaces the bad input instead of returning phantom data.

Source

Thrown at src/officecli/Handlers/Excel/ExcelHandler.Query.cs:455

                sheetNode.Format["colBreaks"] = string.Join(",", cbreaks);
            }

            if (depth > 0)
            {
                sheetNode.Children = GetSheetChildNodes(sheetNameFromPath, data, depth, worksheet);
                // Children omit value-less empty cells/rows (issue #149);
                // reflect the actual listed count, not the raw row count.
                sheetNode.ChildCount = sheetNode.Children.Count;
            }
            return sheetNode;
        }

        // BUG-R41-F2: reject cell reference segments that contain control characters
        // (e.g. \n, \r, \t). Without this check, "A1\n" passes the cell-ref regex
        // (Regex `$` matches before trailing \n in .NET) and resolves to a ghost cell.
        var cellRef = segments[1];
        if (cellRef.Any(c => c < ' ' && c != '\t' || c == '\x7f'))
            throw new ArgumentException(
                $"Cell reference '{cellRef.Replace("\n", "\\n").Replace("\r", "\\r")}' contains invalid control characters. " +
                $"Expected a clean cell address like 'A1' or 'B2'.");

        // Page break path: /Sheet1/rowbreak[N] or /Sheet1/colbreak[N]
        var rbMatch = Regex.Match(cellRef, @"^rowbreak\[(\d+)\]$", RegexOptions.IgnoreCase);
        if (rbMatch.Success)
        {
            var rbIdx = int.Parse(rbMatch.Groups[1].Value);
            var rowBreaks = GetSheet(worksheet).GetFirstChild<RowBreaks>();
            var breaks = rowBreaks?.Elements<Break>().ToList() ?? new();
            if (rbIdx < 1 || rbIdx > breaks.Count)
                throw new ArgumentException($"Row break index {rbIdx} out of range (1-{breaks.Count})");
            var brk = breaks[rbIdx - 1];
            var rbNode = new DocumentNode
            {
                Path = path, Type = "rowbreak",
                Format = { ["row"] = brk.Id?.Value ?? 0u, ["manual"] = brk.ManualPageBreak?.Value ?? false }
            };

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Sanitize the path before Get: strip chars in \x00-\x08, \x0B, \x0C, \x0E-\x1F, \x7F (keep tab only if intended).
  2. .Trim() the cell segment and reject empty results.
  3. Validate with a clean cell-ref regex (^[A-Za-z]{1,3}[0-9]+$) before calling Get.

Example fix

// before
var cell = handler.Get("/Sheet1/" + addr); // addr = "A1\n" -> throws

// after
var clean = Regex.Replace(addr, @"[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]", "").Trim();
var cell = handler.Get($"/Sheet1/{clean}");
Defensive patterns

Strategy: validation

Validate before calling

// strip control chars (except tab) + DEL before Get
var clean = Regex.Replace(path, @"[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]", "");
if (clean != path)
    throw new ArgumentException("Path contained control characters");
return handler.Get(clean);

Type guard

static bool HasControlChars(string cellRef) =>
    cellRef.Any(c => (c < ' ' && c != '\t') || c == '\x7f');

Prevention

When it happens

Trigger: Calling Get with a cell segment carrying \n/\r/\t from unsanitized user input, a clipboard paste, or string concatenation — e.g. handler.Get("/Sheet1/A1\n") or /Sheet1/B2\r. Reading addresses from a DB/CSV column that has trailing newlines.

Common situations: Pasting an address from a cell that includes a newline. Interpolating values read from another source without trimming. Cross-platform line endings (\r\n) leaking into a path segment.

Related errors


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