{"record":{"id":"c711eeedbf6364e0","repo":"larksuite/cli","slug":"invalid-a1-range-range-ref","errorCode":null,"errorMessage":"Invalid A1 range: {range_ref}","messagePattern":"Invalid A1 range: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/lark-sheets/scripts/lark_sheet_range.py","lineNumber":90,"sourceCode":"    raise ValueError(f\"Invalid A1 range endpoint: {endpoint}\")\n\n\ndef parse_range(\n    range_ref: str,\n    *,\n    max_row: int | None = None,\n    max_col: int | None = None,\n) -> RangeBounds:\n    \"\"\"Parse the A1 range forms accepted by ``+csv-get``.\n\n    Open-ended forms need the caller's actual returned grid dimensions. This\n    keeps generated ranges finite without guessing a spreadsheet-wide limit.\n    \"\"\"\n    ref = range_ref.strip()\n    if \"!\" in ref:\n        _, ref = ref.rsplit(\"!\", 1)\n    if not ref:\n        raise ValueError(f\"Invalid A1 range: {range_ref}\")\n    parts = ref.split(\":\")\n    if len(parts) > 2:\n        raise ValueError(f\"Invalid A1 range: {range_ref}\")\n    start = _parse_endpoint(parts[0])\n    end = _parse_endpoint(parts[-1])\n\n    if len(parts) == 1:\n        if start[0] != \"cell\":\n            raise ValueError(f\"A1 range must include a cell or ':' separator: {range_ref}\")\n        _, 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","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/skills/lark-sheets/scripts/lark_sheet_range.py#L72-L108","documentation":"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.","triggerScenarios":"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 ''.","commonSituations":"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.","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\"."],"exampleFix":"// before\nraw = os.environ.get(\"SHEET_RANGE\", \"\")\nparse_range(raw)  # Invalid A1 range: (empty)\n// after\nraw = os.environ.get(\"SHEET_RANGE\", \"A1\")\nif not raw.strip():\n    raise SystemExit(\"SHEET_RANGE must be set\")\nparse_range(raw)","handlingStrategy":"validation","validationCode":"def ensure_range(raw: str) -> str:\n    ref = (raw or \"\").strip().rsplit(\"!\", 1)[-1]\n    if not ref:\n        raise ValueError(\"range is empty; supply e.g. A1:B10\")\n    return ref\n# call: parse_range(ensure_range(user_input))","typeGuard":"def nonempty_range(raw: str | None) -> str | None:\n    if not raw or not raw.strip().rsplit(\"!\", 1)[-1]:\n        return None\n    return raw","tryCatchPattern":"from lark_sheet_range import parse_range\ntry:\n    bounds = parse_range(raw)\nexcept ValueError:\n    bounds = parse_range(\"A1\")  # documented fallback default","preventionTips":["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."],"tags":["python","input-validation","a1-notation","empty-input"],"backgroundTag":"invalid-range-notation","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"}