larksuite/cli · error
end %q must be at or after start %q
Error message
end %q must be at or after start %q
What it means
After both cell references in a range parse successfully, the parser verifies the end cell is not before the start cell in either row or column order. If the end row or end column is smaller than the start's, it rejects the range. The error is intermediate and gets wrapped into a typed validation error with flag/param context by callers.
Source
Thrown at shortcuts/sheets/lark_sheet_workbook.go:2124
rangeStr = strings.TrimSpace(rangeStr)
if rangeStr == "" {
return 0, 0, 0, 0, fmt.Errorf("empty range") //nolint:forbidigo // intermediate error; callers wrap it into a typed validation error with flag/param context
}
parts := strings.SplitN(rangeStr, ":", 2)
if len(parts) == 1 {
col, row, ok := splitCellRef(parts[0])
if !ok {
return 0, 0, 0, 0, fmt.Errorf("invalid cell ref %q", parts[0]) //nolint:forbidigo // intermediate error; callers wrap it into a typed validation error with flag/param context
}
return col, row, col, row, nil
}
startCol, startRow, ok1 := splitCellRef(parts[0])
endCol, endRow, ok2 := splitCellRef(parts[1])
if !ok1 || !ok2 {
return 0, 0, 0, 0, fmt.Errorf("unsupported range form %q (need rectangular A1:B2)", rangeStr) //nolint:forbidigo // intermediate error; callers wrap it into a typed validation error with flag/param context
}
if endRow < startRow || endCol < startCol {
return 0, 0, 0, 0, fmt.Errorf("end %q must be at or after start %q", parts[1], parts[0]) //nolint:forbidigo // intermediate error; callers wrap it into a typed validation error with flag/param context
}
return startCol, startRow, endCol, endRow, nil
}
// mergeWorkbookCreateStyle merges one cell_styles op's style map into a cell.
// cell_styles / border_styles are nested submaps: they are deep-merged one level
// (field-wise, last write wins) so overlapping cell_styles ops accumulate fields
// rather than the later op's submap wholesale-replacing the earlier one. A fresh
// submap is allocated each merge so the op.Style shared across the range's cells
// is never mutated.
func mergeWorkbookCreateStyle(cell interface{}, style map[string]interface{}) {
if len(style) == 0 {
return
}
m, ok := cell.(map[string]interface{})
if !ok {
return
}View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Swap the two cells so the top-left cell comes first, e.g. use 'A1:B2' instead of 'B2:A1'.
- If the range is computed, order start/end by (row, column) before formatting the string.
- Normalize with min/max on column index and row number in generating code.
Example fix
// before --range "B2:A1" // after --range "A1:B2"
Defensive patterns
Strategy: validation
Validate before calling
func normalizeRange(s string) (string, error) {
parts := strings.Split(s, ":")
if len(parts) != 2 { return "", fmt.Errorf("need A1:B2 form") }
if cellKey(parts[0]) > cellKey(parts[1]) { parts[0], parts[1] = parts[1], parts[0] }
return parts[0] + ":" + parts[1], nil
} Type guard
func isOrderedRange(s string) bool {
p := strings.Split(s, ":")
return len(p) == 2 && cellKey(p[0]) <= cellKey(p[1])
} Prevention
- Always order ranges top-left first when constructing them programmatically.
- Normalize user input by swapping start/end if inverted.
When it happens
Trigger: Passing an inverted range to a sheet workbook shortcut, e.g. 'B2:A1' (end column before start column) or 'A5:A1' (end row above start row).
Common situations: Users selecting a range bottom-right to top-left in their head, or programmatically generating ranges where start/end were computed in the wrong order.
Related errors
- unsupported range form %q (need rectangular A1:B2)
- empty range
- invalid cell ref %q
- unsupported range form %q (need rectangular A1:B2)
- end %q must be at or after start %q
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/f89616e504b70f1a.
Report an issue: GitHub.