larksuite/cli · error · ValueError

A1 range must include a cell or ':' separator: {range_ref}

Error message

A1 range must include a cell or ':' separator: {range_ref}

What it means

When parse_range() receives a single endpoint (no ':'), that endpoint must be a cell; a bare row ('5') or column ('A') is only valid as one side of a 'start:end' pair. This error distinguishes a lone row/column endpoint, which has no defined bounds by itself, from a valid single-cell range.

Source

Thrown at skills/lark-sheets/scripts/lark_sheet_range.py:99

    """Parse the A1 range forms accepted by ``+csv-get``.

    Open-ended forms need the caller's actual returned grid dimensions. This
    keeps generated ranges finite without guessing a spreadsheet-wide limit.
    """
    ref = range_ref.strip()
    if "!" in ref:
        _, ref = ref.rsplit("!", 1)
    if not ref:
        raise ValueError(f"Invalid A1 range: {range_ref}")
    parts = ref.split(":")
    if len(parts) > 2:
        raise ValueError(f"Invalid A1 range: {range_ref}")
    start = _parse_endpoint(parts[0])
    end = _parse_endpoint(parts[-1])

    if len(parts) == 1:
        if start[0] != "cell":
            raise ValueError(f"A1 range must include a cell or ':' separator: {range_ref}")
        _, row, col = start
        return RangeBounds(row, col, row, col)

    if start[0] == end[0] == "cell":
        _, start_row, start_col = start
        _, end_row, end_col = end
    elif start[0] == end[0] == "row":
        _, start_row = start
        _, end_row = end
        start_col = 1
        if max_col is None:
            raise ValueError(f"Range needs a maximum column: {range_ref}")
        end_col = max_col
    elif start[0] == end[0] == "column":
        _, start_col = start
        _, end_col = end
        start_row = 1
        if max_row is None:

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. For a whole column, pass 'A:A' (max_row must then be supplied by the caller); for a whole row, pass '5:5' (max_row→max_col semantics apply).
  2. For a single cell, pass the full cell ref 'A1' rather than just the column 'A' or row '5'.
  3. Check code that interpolates start/end — an empty end variable collapses 'A:A' to 'A'; default the end endpoint explicitly.
  4. If you want one cell from row/col integers, build the ref with index_to_col(col) + str(row) before parsing.

Example fix

// before
parse_range("A")    # A1 range must include a cell or ':' separator: A
parse_range("5")    # same error
// after
parse_range("A:A")   # whole column (caller supplies max_row)
parse_range("5:5")   # whole row (caller supplies max_col)
parse_range("A1")    # single cell
Defensive patterns

Strategy: validation

Validate before calling

import re
_CELL = re.compile(r"^\$?[A-Za-z]+\$?[1-9][0-9]*$")
def standalone_endpoint_ok(ref: str) -> bool:
    ref = ref.strip().rsplit("!", 1)[-1]
    if ":" in ref:
        return True   # paired endpoints are allowed to be row/column
    return bool(_CELL.match(ref))  # lone endpoint must be a cell

Type guard

import re
_CELL = re.compile(r"^\$?[A-Za-z]+\$?[1-9][0-9]*$")
def lone_cell(ref: str) -> str | None:
    r = ref.strip().rsplit("!", 1)[-1]
    return r if ":" not in r and _CELL.match(r) else None

Try / catch

from lark_sheet_range import parse_range
try:
    bounds = parse_range(range_ref)
except ValueError as e:
    if "must include a cell" in str(e):
        range_ref = f"{range_ref}:{range_ref}"  # 'A' -> 'A:A', '5' -> '5:5'
        bounds = parse_range(range_ref)
    else:
        raise

Prevention

When it happens

Trigger: parse_range('5'), parse_range('A'), parse_range('$B'), parse_range('AA') — a single row or column endpoint without a ':' and second endpoint. Note 'A1:B' (cell:column) with max_row, or ':A1:B2' variants are handled elsewhere; this fires only for len(parts)==1 with start[0] != 'cell'.

Common situations: Passing just a column letter or row number when a whole-column/whole-row range was intended ('A' instead of 'A:A', '5' instead of '5:5'); config storing only the row/column dimension; dropping the second endpoint when programmatically building a range with an empty end value.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/9d790e1e7c67af79. Report an issue: GitHub.