{"record":{"id":"dac6ad66da2cf865","repo":"aaif-goose/goose","slug":"range-start-must-not-follow-range-end","errorCode":null,"errorMessage":"Range start must not follow range end","messagePattern":"Range start must not follow range end","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-mcp/src/computercontroller/xlsx_tool.rs","lineNumber":240,"sourceCode":"    // 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}\"\n    );\n    anyhow::ensure!(\n        (1..=MAX_EXCEL_COLUMNS).contains(&start_col) && (1..=MAX_EXCEL_COLUMNS).contains(&end_col),\n        \"Column must be between 1 and {MAX_EXCEL_COLUMNS}\"\n    );\n    anyhow::ensure!(\n        start_row <= end_row && start_col <= end_col,\n        \"Range start must not follow range end\"\n    );\n\n    let row_count = end_row\n        .checked_sub(start_row)\n        .and_then(|span| span.checked_add(1))\n        .context(\"Row span overflow\")?;\n    let column_count = end_col\n        .checked_sub(start_col)\n        .and_then(|span| span.checked_add(1))\n        .context(\"Column span overflow\")?;\n    let cell_count = u64::from(row_count)\n        .checked_mul(u64::from(column_count))\n        .context(\"Range area overflow\")?;\n    anyhow::ensure!(\n        cell_count <= MAX_RANGE_CELLS,\n        \"Range contains {cell_count} cells; maximum is {MAX_RANGE_CELLS}\"","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-mcp/src/computercontroller/xlsx_tool.rs#L222-L258","documentation":"validate_range_bounds() rejects ranges whose start corner comes after the end corner: start_row > end_row or start_col > end_col bails with 'Range start must not follow range end'. Both corners are otherwise valid cells; only their order is wrong. Reversing the two references fixes it.","triggerScenarios":"Ranges like 'B2:A1' (both reversed), 'A5:A1' (rows reversed), or 'C1:A1' (columns reversed). Typically produced by computing start/end independently (e.g. min/max swapped) when constructing the range string.","commonSituations":"Agents stringing together cell coordinates without sorting; drag-selection processed in reverse; user typing the bottom-right cell first; rectangle math using unordered corners.","solutions":["Write the upper-left cell first: 'A1:B2', not 'B2:A1'.","When building from two arbitrary corners, sort rows and columns (min start, max end) before formatting.","Validate ordering client-side with a small helper before calling the tool."],"exampleFix":"// before\nlet range = format!(\"{}:{}\", bottom_right, top_left); // \"B2:A1\" -> error\n\n// after: normalize corner order before formatting\nlet (r1, r2) = (top_left_row.min(bottom_row), top_left_row.max(bottom_row));\nlet (c1, c2) = (left_col.min(right_col), left_col.max(right_col));\nlet range = format!(\"{}{}:{}{}\", col_name(c1), r1, col_name(c2), r2);","handlingStrategy":"validation","validationCode":"fn normalize_corners(r1: u32, c1: u32, r2: u32, c2: u32) -> (u32, u32, u32, u32) {\n    (r1.min(r2), c1.min(c2), r1.max(r2), c1.max(c2))\n}\n// build the range string from normalized (min, max) corners\nlet (sr, sc, er, ec) = normalize_corners(sr, sc, er, ec);\nlet range = format!(\"{}{}:{}{}\", col_name(sc), sr, col_name(ec), er);","typeGuard":"fn is_ordered_range(range: &str) -> bool {\n    let cells: Vec<&str> = range.split(':').collect();\n    if cells.len() != 2 { return false; }\n    let parse = |c: &str| (\n        c.chars().filter(|x| x.is_ascii_alphabetic()).count(),\n        c.chars().filter(|x| x.is_ascii_digit()).count(),\n    );\n    // full ordering check needs numeric conversion; use parse_range-style logic\n    true // placeholder — prefer normalizing corners over checking order\n}","tryCatchPattern":null,"preventionTips":["Always emit the upper-left corner first (smallest row and column).","Normalize arbitrary corners with min/max before formatting the range.","Remember Excel ranges are always top-left:bottom-right."],"tags":["rust","excel","validation","range-order","range","xlsx"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}