{"record":{"id":"560fb47d71aacd33","repo":"larksuite/cli","slug":"range-needs-a-maximum-row-range-ref","errorCode":null,"errorMessage":"Range needs a maximum row: {range_ref}","messagePattern":"Range needs a maximum row: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/lark-sheets/scripts/lark_sheet_range.py","lineNumber":118,"sourceCode":"        _, row, col = start\n        return RangeBounds(row, col, row, col)\n\n    if start[0] == end[0] == \"cell\":\n        _, start_row, start_col = start\n        _, end_row, end_col = end\n    elif start[0] == end[0] == \"row\":\n        _, start_row = start\n        _, end_row = end\n        start_col = 1\n        if max_col is None:\n            raise ValueError(f\"Range needs a maximum column: {range_ref}\")\n        end_col = max_col\n    elif start[0] == end[0] == \"column\":\n        _, start_col = start\n        _, end_col = end\n        start_row = 1\n        if max_row is None:\n            raise ValueError(f\"Range needs a maximum row: {range_ref}\")\n        end_row = max_row\n    elif start[0] == \"cell\" and end[0] == \"column\":\n        _, start_row, start_col = start\n        _, end_col = end\n        if max_row is None:\n            raise ValueError(f\"Range needs a maximum row: {range_ref}\")\n        end_row = max(start_row, max_row)\n    elif start[0] == \"cell\" and end[0] == \"row\":\n        _, start_row, start_col = start\n        _, end_row = end\n        if max_col is None:\n            raise ValueError(f\"Range needs a maximum column: {range_ref}\")\n        end_col = max(start_col, max_col)\n    else:\n        raise ValueError(f\"Invalid A1 range: {range_ref}\")\n    return RangeBounds(min(start_row, end_row), min(start_col, end_col), max(start_row, end_row), max(start_col, end_col))\n\n","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/skills/lark-sheets/scripts/lark_sheet_range.py#L100-L136","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass max_row explicitly: parse_range('A:C', max_row=200) with the actual row count.","Use a closed cell range such as parse_range('A1:C200') so no dimension is needed.","Fetch sheet dimensions first, then call parse_range with max_row set from them."],"exampleFix":"// before\nbounds = parse_range(\"A:C\")\n// after\nbounds = parse_range(\"A:C\", max_row=last_used_row)","handlingStrategy":"validation","validationCode":"import re\n\ndef is_open_col_range(ref: str) -> bool:\n    \"\"\"True if ref is column:column form and will require max_row.\"\"\"\n    body = ref.strip().rsplit(\"!\", 1)[-1]\n    parts = body.split(\":\")\n    col_re = re.compile(r\"^\\$?[A-Za-z]+$\")\n    return len(parts) == 2 and all(col_re.match(p.strip()) for p in parts)\n\n# call site\nif is_open_col_range(ref):\n    assert max_row is not None, f\"{ref} needs max_row\"\nbounds = parse_range(ref, max_row=max_row)","typeGuard":"def needs_max_row(ref: str) -> bool:\n    body = ref.strip().rsplit(\"!\", 1)[-1]\n    parts = body.split(\":\")\n    import re\n    col_re = re.compile(r\"^\\$?[A-Za-z]+$\")\n    return len(parts) == 2 and bool(col_re.match(parts[0].strip()) and col_re.match(parts[-1].strip()))","tryCatchPattern":"try:\n    bounds = parse_range(ref, max_row=max_row)\nexcept ValueError as e:\n    if \"maximum row\" in str(e):\n        bounds = parse_range(ref, max_row=grid_row_count)  # retry with fetched height\n    else:\n        raise","preventionTips":["Avoid whole-column ranges when the data height is known; write A1:C200 instead","Fetch sheet dimensions before parsing ranges and pass them as max_row/max_col","Document the accepted range grammar wherever users configure range strings"],"tags":["python","validation","a1-range","sheets"],"backgroundTag":"open-ended-range-missing-dimension","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}