{"record":{"id":"51a3540dc4f9cb85","repo":"aaif-goose/goose","slug":"invalid-range-format-expected-format-a1-b10","errorCode":null,"errorMessage":"Invalid range format. Expected format: 'A1:B10'","messagePattern":"Invalid range format\\. Expected format: 'A1:B10'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-mcp/src/computercontroller/xlsx_tool.rs","lineNumber":216,"sourceCode":"    pub fn get_cell_value(&self, worksheet: &Worksheet, row: u32, col: u32) -> Result<CellValue> {\n        let cell = worksheet.cell((col, row)).context(\"Cell not found\")?;\n\n        Ok(CellValue {\n            value: cell.value().into_owned(),\n            formula: if cell.formula().is_empty() {\n                None\n            } else {\n                Some(cell.formula().to_string())\n            },\n        })\n    }\n}\n\nfn parse_range(range: &str) -> Result<(u32, u32, u32, u32)> {\n    // Handle ranges like \"A1:B10\" and return (start_row, start_col, end_row, end_col)\n    let parts: Vec<&str> = range.split(':').collect();\n    if parts.len() != 2 {\n        anyhow::bail!(\"Invalid range format. Expected format: 'A1:B10'\");\n    }\n\n    let start = parse_cell_reference(parts[0])?;\n    let end = parse_cell_reference(parts[1])?;\n\n    // parse_cell_reference returns (row, col), so start.0 is row, start.1 is col\n    Ok((start.0, start.1, end.0, end.1))\n}\n\nfn validate_range_bounds(\n    start_row: u32,\n    start_col: u32,\n    end_row: u32,\n    end_col: u32,\n) -> Result<(u32, u32)> {\n    anyhow::ensure!(\n        (1..=MAX_EXCEL_ROWS).contains(&start_row) && (1..=MAX_EXCEL_ROWS).contains(&end_row),\n        \"Row must be between 1 and {MAX_EXCEL_ROWS}\"","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-mcp/src/computercontroller/xlsx_tool.rs#L198-L234","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass a full range: 'A1:B10' format, exactly one colon.","For a single cell, duplicate it: 'A1:A1'.","Trim whitespace and uppercase the string before calling the tool.","Have the agent validate the range with a regex before invoking the tool."],"exampleFix":"// before\nlet data = spreadsheet.get_range(&ws, \"A1\")?; // -> Invalid range format\n\n// after\nlet data = spreadsheet.get_range(&ws, \"A1:A1\")?;","handlingStrategy":"validation","validationCode":"fn normalize_range(range: &str) -> String {\n    let r = range.trim().to_uppercase();\n    if r.contains(':') { r } else { format!(\"{r}:{r}\") } // single cell -> A1:A1\n}\nlet range = normalize_range(raw);\nanyhow::ensure!(range.matches(':').count() == 1, \"range must look like 'A1:B10'\");","typeGuard":"fn is_valid_excel_range_format(range: &str) -> bool {\n    let re = regex::Regex::new(\n        r\"^[A-Za-z]{1,3}[1-9][0-9]{0,6}:[A-Za-z]{1,3}[1-9][0-9]{0,6}$\"\n    ).unwrap();\n    re.is_match(range.trim())\n}","tryCatchPattern":null,"preventionTips":["Always send two colon-separated corners, even for a single cell ('A1:A1').","Trim and uppercase the range before calling the tool.","Have agents run the regex guard before emitting a tool call."],"tags":["rust","excel","validation","range","xlsx","computercontroller"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}