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 = endView on GitHub (pinned to 7fd6ef3c07)
Solutions
- Provide an actual range like 'A1:B10' — check the variable feeding parse_range is non-empty before calling.
- If a sheet prefix is present, ensure content follows the '!': 'Sheet1!A1' not 'Sheet1!'.
- 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
- Give config/env range fields a concrete default (e.g. 'A1') instead of ''.
- Validate that a 'Sheet!' prefix is followed by content before parsing.
- Never interpolate optional values into range strings without an emptiness check.
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
- Invalid cell reference: {cell_ref}
- Invalid A1 range endpoint: {endpoint}
- A1 range must include a cell or ':' separator: {range_ref}
- Invalid column: {col}
- Column index must be >= 1: {index}
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/c711eeedbf6364e0.
Report an issue: GitHub.