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
- Use 1-based rows within 1..=1048576 (e.g. 'A1:A1048576' at most).
- Replace row 0 with 1 when converting 0-based client coordinates.
- Clamp requested end rows to 1048576 before calling the tool.
- 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
- Rows are 1-based: convert 0-based client coordinates by adding 1.
- Clamp end rows to 1_048_576; never request 'whole column' as max-row ranges.
- Page through large sheets in bounded windows instead.
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
- Column must be between 1 and {MAX_EXCEL_COLUMNS}
- Invalid range format. Expected format: 'A1:B10'
- Range start must not follow range end
- Range contains {cell_count} cells; maximum is {MAX_RANGE_CEL
- Invalid model spec '{}': expected format 'user/repo:quantiza
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/c6ad25e80a2983a6.
Report an issue: GitHub.