aaif-goose/goose · error

Row must be between 1 and {MAX_EXCEL_ROWS}

Error message

Row must be between 1 and {MAX_EXCEL_ROWS}

What it means

validate_range_bounds() checks that both row numbers fall in 1..=MAX_EXCEL_ROWS (1_048_576 — Excel's real row limit, defined at xlsx_tool.rs:6). Rows are 1-based, so row 0 from 'A0' is invalid, as is anything above 1048576. The message interpolates the actual limit when formatted.

Source

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

    let parts: Vec<&str> = range.split(':').collect();
    if parts.len() != 2 {
        anyhow::bail!("Invalid range format. Expected format: 'A1:B10'");
    }

    let start = parse_cell_reference(parts[0])?;
    let end = parse_cell_reference(parts[1])?;

    // 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)

View on GitHub (pinned to 3810898a74)

Solutions

  1. Use 1-based rows within 1..=1048576 (e.g. 'A1:A1048576' at most).
  2. Replace row 0 with 1 when converting 0-based client coordinates.
  3. Clamp requested end rows to 1048576 before calling the tool.
  4. For large sheets, page through ranges in chunks instead of requesting full columns.

Example fix

// before
let range = "A0:A10"; // row 0 invalid -> 'Row must be between 1 and 1048576'

// after
let range = "A1:A10";
Defensive patterns

Strategy: validation

Validate before calling

const MAX_ROWS: u32 = 1_048_576;
fn rows_in_bounds(range: &str) -> bool {
    range.split(':').all(|cell| {
        let row: u32 = cell.trim_start_matches(|c: char| c.is_ascii_alphabetic())
            .parse().unwrap_or(0);
        (1..=MAX_ROWS).contains(&row)
    })
}
assert!(rows_in_bounds(range), "rows must be 1..={MAX_ROWS}");

Type guard

fn has_valid_rows(range: &str) -> bool {
    range.split(':').all(|cell| {
        let digits: String = cell.chars().skip_while(|c| c.is_ascii_alphabetic()).collect();
        matches!(digits.parse::<u32>(), Ok(n) if (1..=1_048_576).contains(&n))
    })
}

Prevention

When it happens

Trigger: Ranges like 'A0:A10' (zero row), 'A1:A9999999' (row past the cap), or agents computing end_row as start_row + oversize offset that overflows the limit. Any get_range() call runs this check after parse_range.

Common situations: Whole-column requests translated to 'A1:A9999999'; off-by-one bugs producing row 0; LLM-generated ranges hallucinating 'row 2000000'; data imported from tools that use 0-based coordinates.

Related errors


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