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 halves of a colon-separated range parse, parseCellRange checks that the end cell is at or after the start cell in both row and column. An inverted range like 'B2:A1' or 'A5:A1' is rejected. Callers wrap this into a typed --range/--source-range validation error with flag/param context.

Source

Thrown at shortcuts/sheets/lark_sheet_write_cells.go:1159

	}
	parts := strings.SplitN(body, ":", 2)
	out.start = strings.TrimSpace(parts[0])
	startCol, startRow, ok := splitCellRef(out.start)
	out.col, out.row = startCol, startRow
	if len(parts) == 1 {
		// single cell, e.g. "A1"
		if !ok {
			return cellRange{}, fmt.Errorf("invalid cell ref %q", parts[0]) //nolint:forbidigo // intermediate error; callers wrap it into a typed --range/--source-range validation error
		}
		out.rows, out.cols, out.anchored = 1, 1, true
		return out, nil
	}
	endCol, endRow, okEnd := splitCellRef(parts[1])
	if !ok || !okEnd {
		return cellRange{}, fmt.Errorf("unsupported range form %q (need rectangular A1:B2)", body) //nolint:forbidigo // intermediate error; callers wrap it into a typed --range/--source-range validation error
	}
	if endRow < startRow || endCol < startCol {
		return cellRange{}, 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 --range/--source-range validation error
	}
	out.rows, out.cols = endRow-startRow+1, endCol-startCol+1
	return out, nil
}

func rangeDimensions(rangeStr string) (rows, cols int, err error) {
	r, err := parseCellRange(rangeStr)
	if err != nil {
		return 0, 0, err
	}
	return r.rows, r.cols, nil
}

// splitCellRef parses "A1" → (col=0, row=0, true). Returns false for any
// non-rectangular form (pure column "A", pure row "1", invalid chars).
func splitCellRef(s string) (col, row int, ok bool) {
	s = strings.TrimSpace(s)
	if s == "" {

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Order the range top-left first: swap the cells, e.g. 'A1:B2' instead of 'B2:A1'.
  2. In generating code, compute start = min corner and end = max corner of the rectangle.
  3. Sanitize user input by normalizing row/col ordering before invoking the command.

Example fix

// before
--range "A5:A1"
// after
--range "A1:A5"
Defensive patterns

Strategy: validation

Validate before calling

a, b := parseKey(parts[0]), parseKey(parts[1])
if a > b { parts[0], parts[1] = parts[1], parts[0] } // normalize before calling the CLI

Type guard

func isOrderedRange(s string) bool {
	p := strings.Split(s, ":")
	return len(p) == 2 && cellKey(p[0]) <= cellKey(p[1])
}

Prevention

When it happens

Trigger: Passing a range whose end cell has a smaller row number or column index than the start cell, e.g. 'B2:A1', 'A5:A1', 'C1:B3'.

Common situations: Users specifying ranges right-to-left or bottom-to-top, or code emitting ranges from an unordered selection rectangle.

Related errors


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