aaif-goose/goose · error

Column must be between 1 and {MAX_EXCEL_COLUMNS}

Error message

Column must be between 1 and {MAX_EXCEL_COLUMNS}

What it means

validate_range_bounds() requires both column numbers within 1..=MAX_EXCEL_COLUMNS (16_384, i.e. column 'XFD', defined at xlsx_tool.rs:7). Columns beyond XFD — 'XFE', 'ZZZ', 'AAAA' — parse to numbers over the cap and trigger this bail. Excel itself has the same limit, so such ranges cannot exist in a valid workbook.

Source

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

    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)
        .and_then(|span| span.checked_add(1))
        .context("Column span overflow")?;
    let cell_count = u64::from(row_count)
        .checked_mul(u64::from(column_count))

View on GitHub (pinned to 3810898a74)

Solutions

  1. Keep columns within A..XFD (1..=16384).
  2. Validate/convert numeric column indices with a cap of 16384 before building the range string.
  3. If the data really needs more columns, it exceeds xlsx format limits — restructure the data.
  4. Check the worksheet's highest_column() and clamp the range to actual used columns.

Example fix

// before
let range = "A1:ZZZ1"; // 702 > 16384? no — ZZZ=18278 -> column bound error

// after
let range = "A1:XFD1"; // 16384 = last valid column
Defensive patterns

Strategy: validation

Validate before calling

fn col_to_index(letters: &str) -> u32 {
    letters.bytes().fold(0u32, |acc, b| acc * 26 + u32::from(b - b'A' + 1))
}
fn cols_in_bounds(range: &str) -> bool {
    range.split(':').all(|cell| {
        let letters: String = cell.chars().take_while(|c| c.is_ascii_alphabetic()).collect();
        (1..=16_384).contains(&col_to_index(&letters.to_uppercase()))
    })
}
assert!(cols_in_bounds(range), "columns must be within A..XFD");

Type guard

fn has_valid_columns(range: &str) -> bool {
    let val = |cell: &str| -> u32 {
        cell.chars().take_while(|c| c.is_ascii_alphabetic())
            .fold(0, |acc, c| acc * 26 + (c.to_ascii_uppercase() as u32 - 'A' as u32 + 1))
    };
    range.split(':').all(|cell| (1..=16_384).contains(&val(cell)))
}

Prevention

When it happens

Trigger: Ranges like 'XFE1:XFE10' (16385), 'ZZZ1:ZZZ1', or agents inventing wide-column addresses. Column letters are parsed case-insensitively, so case is not the issue — only the magnitude.

Common situations: LLM-generated ranges hallucinating far-right columns; converting numeric column indices (e.g. 20000) to letters without bounds awareness; spreadsheets migrated from other tools claiming wider grids.

Related errors


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