larksuite/cli · error · ValueError

Invalid A1 range: {range_ref}

Error message

Invalid A1 range: {range_ref}

What it means

parse_range() normalizes the range string (stripping whitespace and a trailing 'Sheet!' prefix) and raises ValueError when the remaining reference is empty — i.e. the input was blank, whitespace-only, or ended with '!' leaving nothing after the last '!'. It guards against constructing degenerate range bounds from an empty string.

Source

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

    raise ValueError(f"Invalid A1 range endpoint: {endpoint}")


def parse_range(
    range_ref: str,
    *,
    max_row: int | None = None,
    max_col: int | None = None,
) -> RangeBounds:
    """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

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Provide an actual range like 'A1:B10' — check the variable feeding parse_range is non-empty before calling.
  2. If a sheet prefix is present, ensure content follows the '!': 'Sheet1!A1' not 'Sheet1!'.
  3. Default to a concrete range in config/code when the value is missing, e.g. range = raw or "A1".

Example fix

// before
raw = os.environ.get("SHEET_RANGE", "")
parse_range(raw)  # Invalid A1 range: (empty)
// after
raw = os.environ.get("SHEET_RANGE", "A1")
if not raw.strip():
    raise SystemExit("SHEET_RANGE must be set")
parse_range(raw)
Defensive patterns

Strategy: validation

Validate before calling

def ensure_range(raw: str) -> str:
    ref = (raw or "").strip().rsplit("!", 1)[-1]
    if not ref:
        raise ValueError("range is empty; supply e.g. A1:B10")
    return ref
# call: parse_range(ensure_range(user_input))

Type guard

def nonempty_range(raw: str | None) -> str | None:
    if not raw or not raw.strip().rsplit("!", 1)[-1]:
        return None
    return raw

Try / catch

from lark_sheet_range import parse_range
try:
    bounds = parse_range(raw)
except ValueError:
    bounds = parse_range("A1")  # documented fallback default

Prevention

When it happens

Trigger: parse_range(''), parse_range(' '), parse_range('Sheet1!') — anything where after strip and rsplit('!', 1) the ref is ''. Also a caller variable that is an empty string because a config field or CLI argument defaulted to ''.

Common situations: Empty environment variable or config key used as the range; f-string interpolation of an optional value that was None→'' ... actually None would crash earlier; 'Sheet1!' copied from a spreadsheet UI with the range part cut off; split operations yielding an empty tail.

Related errors


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