{"record":{"id":"e640c4daf87044e9","repo":"PHPOffice/PhpSpreadsheet","slug":"you-tried-to-remove-a-sheet-by-the-out-of-bounds-i","errorCode":null,"errorMessage":"You tried to remove a sheet by the out of bounds index: {$sheetIndex}. The actual number of sheets is {$numSheets}.","messagePattern":"You tried to remove a sheet by the out of bounds index: (.+?)\\. The actual number of sheets is (.+?)\\.","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Spreadsheet.php","lineNumber":675,"sourceCode":"        }\n\n        if ($worksheet->getParent() === null) {\n            $worksheet->rebindParent($this);\n        }\n\n        return $worksheet;\n    }\n\n    /**\n     * Remove sheet by index.\n     *\n     * @param int $sheetIndex Index position of the worksheet to remove\n     */\n    public function removeSheetByIndex(int $sheetIndex): void\n    {\n        $numSheets = count($this->workSheetCollection);\n        if ($sheetIndex > $numSheets - 1) {\n            throw new Exception(\n                \"You tried to remove a sheet by the out of bounds index: {$sheetIndex}. The actual number of sheets is {$numSheets}.\"\n            );\n        }\n        array_splice($this->workSheetCollection, $sheetIndex, 1);\n\n        // Adjust active sheet index if necessary\n        if (\n            ($this->activeSheetIndex >= $sheetIndex)\n            && ($this->activeSheetIndex > 0 || $numSheets <= 1)\n        ) {\n            --$this->activeSheetIndex;\n        }\n    }\n\n    /**\n     * Get sheet by index.\n     *\n     * @param int $sheetIndex Sheet index","sourceCodeStart":657,"sourceCodeEnd":693,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Spreadsheet.php#L657-L693","documentation":"Spreadsheet::removeSheetByIndex() validates the requested index against count(workSheetCollection). The guard only catches indices greater than count-1; any index within 0..count-1 is passed to array_splice(). The message reports both the requested index and the real sheet count so you can see the mismatch. Note the check is an upper-bound check only.","triggerScenarios":"removeSheetByIndex($spreadsheet->getSheetCount()) (off-by-one: valid indices are 0..count-1); a hard-coded index like removeSheetByIndex(3) on a workbook that has fewer sheets; looping over a count captured before earlier removals shrank the collection.","commonSituations":"Import/merge scripts that drop 'raw data' sheets by position after processing; user input used as a sheet number (1-based from a UI vs 0-based API); deleting several sheets in a loop without re-counting.","solutions":["Validate first: if ($i < 0 || $i >= $spreadsheet->getSheetCount()) abort; only then removeSheetByIndex($i).","When removing several sheets by index, iterate from the highest index down so earlier removals do not shift later indices.","If the user supplies a 1-based number, subtract 1 before calling the 0-based API.","Prefer removing by name via getSheetByName()/getIndex() when the target is identified by title."],"exampleFix":"// before\n$spreadsheet->removeSheetByIndex(3); // throws when only 3 sheets (0..2)\n\n// after\n$index = 3;\nif ($index < $spreadsheet->getSheetCount()) {\n    $spreadsheet->removeSheetByIndex($index);\n}","handlingStrategy":"validation","validationCode":"if ($sheetIndex >= 0 && $sheetIndex < $spreadsheet->getSheetCount()) {\n    $spreadsheet->removeSheetByIndex($sheetIndex);\n} else {\n    throw new \\InvalidArgumentException(\"Invalid sheet index $sheetIndex\");\n}","typeGuard":"function isValidSheetIndex(\\PhpOffice\\PhpSpreadsheet\\Spreadsheet $s, int $i): bool\n{\n    return $i >= 0 && $i < $s->getSheetCount();\n}","tryCatchPattern":"try {\n    $spreadsheet->removeSheetByIndex($i);\n} catch (\\PhpOffice\\PhpSpreadsheet\\Exception $e) {\n    // index stale after earlier removals — re-count and skip\n    error_log('Skipping removal, sheet already gone: ' . $e->getMessage());\n}","preventionTips":["Convert 1-based UI numbers to 0-based before calling.","Remove multiple sheets from the highest index down.","Re-count with getSheetCount() at call time inside loops."],"tags":["worksheet","index-out-of-bounds","remove-sheet","phpspreadsheet"],"backgroundTag":"index-out-of-bounds","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}