larksuite/cli · error · ValueError

Range needs a maximum row: {range_ref}

Error message

Range needs a maximum row: {range_ref}

What it means

parse_range() raises this when an open-ended column range like 'A:C' is given but the caller did not pass max_row. A column-only range has no bottom edge, so the library requires the caller's actual row count instead of guessing a spreadsheet-wide limit.

Source

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

        _, 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:
            raise ValueError(f"Range needs a maximum row: {range_ref}")
        end_row = max_row
    elif start[0] == "cell" and end[0] == "column":
        _, start_row, start_col = start
        _, end_col = end
        if max_row is None:
            raise ValueError(f"Range needs a maximum row: {range_ref}")
        end_row = max(start_row, max_row)
    elif start[0] == "cell" and end[0] == "row":
        _, start_row, start_col = start
        _, end_row = end
        if max_col is None:
            raise ValueError(f"Range needs a maximum column: {range_ref}")
        end_col = max(start_col, max_col)
    else:
        raise ValueError(f"Invalid A1 range: {range_ref}")
    return RangeBounds(min(start_row, end_row), min(start_col, end_col), max(start_row, end_row), max(start_col, end_col))

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Pass max_row explicitly: parse_range('A:C', max_row=200) with the actual row count.
  2. Use a closed cell range such as parse_range('A1:C200') so no dimension is needed.
  3. Fetch sheet dimensions first, then call parse_range with max_row set from them.

Example fix

// before
bounds = parse_range("A:C")
// after
bounds = parse_range("A:C", max_row=last_used_row)
Defensive patterns

Strategy: validation

Validate before calling

import re

def is_open_col_range(ref: str) -> bool:
    """True if ref is column:column form and will require max_row."""
    body = ref.strip().rsplit("!", 1)[-1]
    parts = body.split(":")
    col_re = re.compile(r"^\$?[A-Za-z]+$")
    return len(parts) == 2 and all(col_re.match(p.strip()) for p in parts)

# call site
if is_open_col_range(ref):
    assert max_row is not None, f"{ref} needs max_row"
bounds = parse_range(ref, max_row=max_row)

Type guard

def needs_max_row(ref: str) -> bool:
    body = ref.strip().rsplit("!", 1)[-1]
    parts = body.split(":")
    import re
    col_re = re.compile(r"^\$?[A-Za-z]+$")
    return len(parts) == 2 and bool(col_re.match(parts[0].strip()) and col_re.match(parts[-1].strip()))

Try / catch

try:
    bounds = parse_range(ref, max_row=max_row)
except ValueError as e:
    if "maximum row" in str(e):
        bounds = parse_range(ref, max_row=grid_row_count)  # retry with fetched height
    else:
        raise

Prevention

When it happens

Trigger: Calling parse_range('A:C') without max_row, or wrappers (parse_annotated_csv, _external_merge_anchors, build_occupancy, profile_grid) receiving a column-range while the fetched grid height is unknown.

Common situations: Configuring an export with a whole-column range ('B:D') before knowing how many rows the sheet has; scripts that hardcode column ranges but forget to thread the fetched row count into parse_range.

Related errors


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