aaif-goose/goose · error

Range start must not follow range end

Error message

Range start must not follow range end

What it means

validate_range_bounds() rejects ranges whose start corner comes after the end corner: start_row > end_row or start_col > end_col bails with 'Range start must not follow range end'. Both corners are otherwise valid cells; only their order is wrong. Reversing the two references fixes it.

Source

Thrown at crates/goose-mcp/src/computercontroller/xlsx_tool.rs:240

    // parse_cell_reference returns (row, col), so start.0 is row, start.1 is col
    Ok((start.0, start.1, end.0, end.1))
}

fn validate_range_bounds(
    start_row: u32,
    start_col: u32,
    end_row: u32,
    end_col: u32,
) -> Result<(u32, u32)> {
    anyhow::ensure!(
        (1..=MAX_EXCEL_ROWS).contains(&start_row) && (1..=MAX_EXCEL_ROWS).contains(&end_row),
        "Row must be between 1 and {MAX_EXCEL_ROWS}"
    );
    anyhow::ensure!(
        (1..=MAX_EXCEL_COLUMNS).contains(&start_col) && (1..=MAX_EXCEL_COLUMNS).contains(&end_col),
        "Column must be between 1 and {MAX_EXCEL_COLUMNS}"
    );
    anyhow::ensure!(
        start_row <= end_row && start_col <= end_col,
        "Range start must not follow range end"
    );

    let row_count = end_row
        .checked_sub(start_row)
        .and_then(|span| span.checked_add(1))
        .context("Row span overflow")?;
    let column_count = end_col
        .checked_sub(start_col)
        .and_then(|span| span.checked_add(1))
        .context("Column span overflow")?;
    let cell_count = u64::from(row_count)
        .checked_mul(u64::from(column_count))
        .context("Range area overflow")?;
    anyhow::ensure!(
        cell_count <= MAX_RANGE_CELLS,
        "Range contains {cell_count} cells; maximum is {MAX_RANGE_CELLS}"

View on GitHub (pinned to 3810898a74)

Solutions

  1. Write the upper-left cell first: 'A1:B2', not 'B2:A1'.
  2. When building from two arbitrary corners, sort rows and columns (min start, max end) before formatting.
  3. Validate ordering client-side with a small helper before calling the tool.

Example fix

// before
let range = format!("{}:{}", bottom_right, top_left); // "B2:A1" -> error

// after: normalize corner order before formatting
let (r1, r2) = (top_left_row.min(bottom_row), top_left_row.max(bottom_row));
let (c1, c2) = (left_col.min(right_col), left_col.max(right_col));
let range = format!("{}{}:{}{}", col_name(c1), r1, col_name(c2), r2);
Defensive patterns

Strategy: validation

Validate before calling

fn normalize_corners(r1: u32, c1: u32, r2: u32, c2: u32) -> (u32, u32, u32, u32) {
    (r1.min(r2), c1.min(c2), r1.max(r2), c1.max(c2))
}
// build the range string from normalized (min, max) corners
let (sr, sc, er, ec) = normalize_corners(sr, sc, er, ec);
let range = format!("{}{}:{}{}", col_name(sc), sr, col_name(ec), er);

Type guard

fn is_ordered_range(range: &str) -> bool {
    let cells: Vec<&str> = range.split(':').collect();
    if cells.len() != 2 { return false; }
    let parse = |c: &str| (
        c.chars().filter(|x| x.is_ascii_alphabetic()).count(),
        c.chars().filter(|x| x.is_ascii_digit()).count(),
    );
    // full ordering check needs numeric conversion; use parse_range-style logic
    true // placeholder — prefer normalizing corners over checking order
}

Prevention

When it happens

Trigger: Ranges like 'B2:A1' (both reversed), 'A5:A1' (rows reversed), or 'C1:A1' (columns reversed). Typically produced by computing start/end independently (e.g. min/max swapped) when constructing the range string.

Common situations: Agents stringing together cell coordinates without sorting; drag-selection processed in reverse; user typing the bottom-right cell first; rectangle math using unordered corners.

Related errors


AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16). Data as JSON: /api/errors/dac6ad66da2cf865. Report an issue: GitHub.