aaif-goose/goose · error

Invalid range format. Expected format: 'A1:B10'

Error message

Invalid range format. Expected format: 'A1:B10'

What it means

parse_range() in the computercontroller xlsx tool requires a range of exactly two colon-separated cell references, 'A1:B10'. Splitting on ':' must yield exactly 2 parts or it bails with this message. The two halves are then parsed by parse_cell_reference (letters then digits, e.g. 'B10'); malformed halves raise their own errors.

Source

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

    pub fn get_cell_value(&self, worksheet: &Worksheet, row: u32, col: u32) -> Result<CellValue> {
        let cell = worksheet.cell((col, row)).context("Cell not found")?;

        Ok(CellValue {
            value: cell.value().into_owned(),
            formula: if cell.formula().is_empty() {
                None
            } else {
                Some(cell.formula().to_string())
            },
        })
    }
}

fn parse_range(range: &str) -> Result<(u32, u32, u32, u32)> {
    // Handle ranges like "A1:B10" and return (start_row, start_col, end_row, end_col)
    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}"

View on GitHub (pinned to 3810898a74)

Solutions

  1. Pass a full range: 'A1:B10' format, exactly one colon.
  2. For a single cell, duplicate it: 'A1:A1'.
  3. Trim whitespace and uppercase the string before calling the tool.
  4. Have the agent validate the range with a regex before invoking the tool.

Example fix

// before
let data = spreadsheet.get_range(&ws, "A1")?; // -> Invalid range format

// after
let data = spreadsheet.get_range(&ws, "A1:A1")?;
Defensive patterns

Strategy: validation

Validate before calling

fn normalize_range(range: &str) -> String {
    let r = range.trim().to_uppercase();
    if r.contains(':') { r } else { format!("{r}:{r}") } // single cell -> A1:A1
}
let range = normalize_range(raw);
anyhow::ensure!(range.matches(':').count() == 1, "range must look like 'A1:B10'");

Type guard

fn is_valid_excel_range_format(range: &str) -> bool {
    let re = regex::Regex::new(
        r"^[A-Za-z]{1,3}[1-9][0-9]{0,6}:[A-Za-z]{1,3}[1-9][0-9]{0,6}$"
    ).unwrap();
    re.is_match(range.trim())
}

Prevention

When it happens

Trigger: Calling the spreadsheet read/range tool with 'A1' (single cell, no colon), 'A1:B2:C3' (two colons), '' or ':' (empty parts), or 'A1 :' with spaces. Any get_range() call funnels through parse_range first.

Common situations: LLM agents constructing the range string and omitting the colon; users copying a single-cell address from Excel's name box; localized Excel installs using a different separator; trailing whitespace not trimmed.

Related errors


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