larksuite/cli · error · ValueError
Row must be >= 1: {row}
Error message
Row must be >= 1: {row} What it means
format_cell() in lark_sheet_range.py validates that a row index is a positive 1-based integer before converting (row, col) to an A1 notation cell reference like "B3". Sheets use 1-based rows, so row 0 or negative rows cannot map to a valid A1 cell. The library raises ValueError immediately to prevent emitting a malformed range string to the Sheets API.
Source
Thrown at skills/lark-sheets/scripts/lark_sheet_range.py:139
_, 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))
def format_cell(row: int, col: int) -> str:
if row < 1:
raise ValueError(f"Row must be >= 1: {row}")
return f"{index_to_col(col)}{row}"
def format_range(start_row: int, start_col: int, end_row: int, end_col: int) -> str:
bounds = RangeBounds(
min(start_row, end_row),
min(start_col, end_col),
max(start_row, end_row),
max(start_col, end_col),
)
start = format_cell(bounds.start_row, bounds.start_col)
end = format_cell(bounds.end_row, bounds.end_col)
return start if start == end else f"{start}:{end}"
def iter_cells(bounds: RangeBounds):
for row in range(bounds.start_row, bounds.end_row + 1):
for col in range(bounds.start_col, bounds.end_col + 1):View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Pass a 1-based row: add 1 to any 0-based index before calling format_cell.
- Clamp or validate computed rows: if row < 1, fix the loop/slice bounds that produced it instead of coercing.
- If you truly need an open-ended range, use format_range with explicit bounds or pass a column-only boundary the range formatter supports, rather than row 0.
Example fix
// before row_idx = rows.index(target) # 0-based ref = format_cell(row_idx, col) # ValueError: Row must be >= 1: 0 // after ref = format_cell(rows.index(target) + 1, col) # 1-based A1 row
Defensive patterns
Strategy: validation
Validate before calling
def safe_format_cell(row, col):
if not isinstance(row, int) or row < 1:
raise ValueError(f"row must be a 1-based int >= 1, got {row!r}")
return format_cell(row, col) Type guard
def is_valid_row(row) -> bool:
return isinstance(row, int) and not isinstance(row, bool) and row >= 1 Try / catch
try:
ref = format_cell(row, col)
except ValueError:
ref = format_cell(max(row, 1), col) # or fix the index source Prevention
- Always convert 0-based indices with +1 immediately before A1 formatting.
- Add an assert row >= 1 at the boundary where indices are computed.
- Prefer format_range with explicit bounds over manual cell strings.
When it happens
Trigger: Calling format_cell(row, col) with row < 1, e.g. format_cell(0, 1) or format_cell(-1, 5), typically from format_range or a caller passing a computed row that was decremented to 0.
Common situations: Developers converting 0-based array indices to A1 notation and forgetting the +1; off-by-one loops that decrement the row before formatting; slicing list rows with [start-1:end] and passing the adjusted index instead of the 1-based one.
Related errors
- Column index must be >= 1: {index}
- Invalid column: {col}
- Invalid cell reference: {cell_ref}
- Invalid A1 range endpoint: {endpoint}
- Invalid A1 range: {range_ref}
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/268251e8ce44875d.
Report an issue: GitHub.