{"record":{"id":"99071324f4b97cde","repo":"PHPOffice/PhpSpreadsheet","slug":"first-sheet-index-must-be-a-positive-integer","errorCode":null,"errorMessage":"First sheet index must be a positive integer.","messagePattern":"First sheet index must be a positive integer\\.","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Spreadsheet.php","lineNumber":1639,"sourceCode":"     *\n     * @return int First sheet in book view\n     */\n    public function getFirstSheetIndex(): int\n    {\n        return $this->firstSheetIndex;\n    }\n\n    /**\n     * Set the first sheet in the book view.\n     *\n     * @param int $firstSheetIndex First sheet in book view\n     */\n    public function setFirstSheetIndex(int $firstSheetIndex): void\n    {\n        if ($firstSheetIndex >= 0) {\n            $this->firstSheetIndex = (int) $firstSheetIndex;\n        } else {\n            throw new Exception('First sheet index must be a positive integer.');\n        }\n    }\n\n    /**\n     * Return the visibility status of the workbook.\n     *\n     * This may be one of the following three values:\n     * - visibile\n     *\n     * @return string Visible status\n     */\n    public function getVisibility(): string\n    {\n        return $this->visibility;\n    }\n\n    /**\n     * Set the visibility status of the workbook.","sourceCodeStart":1621,"sourceCodeEnd":1657,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Spreadsheet.php#L1621-L1657","documentation":"Spreadsheet::setFirstSheetIndex(int) sets which tab the workbook view scrolls to first (the first visible tab in the sheet tab bar when the file opens). Any value below zero throws 'First sheet index must be a positive integer.' — although the message says 'positive', the code actually accepts 0 (the first sheet); only negatives are rejected.","triggerScenarios":"setFirstSheetIndex(-1) from an off-by-one computation (e.g. $index - 1 when $index is 0); passing a 'not selected' sentinel like -1 from UI code; arithmetic on an index variable that can legitimately reach -1.","commonSituations":"Form/CLI input where 'no preference' is encoded as -1 and forwarded verbatim; computations like setFirstSheetIndex($activeIndex - 1) used to show the tab before the active one; casting null or failed intval() input (0 is fine, but -1 sentinels are not).","solutions":["Clamp to a valid range: $first = max(0, min($first, $spreadsheet->getSheetCount() - 1)); before calling.","Map 'no preference' sentinels (-1, null) to 0 explicitly instead of passing them through.","Use setActiveSheetIndexByName()/by valid index when the intent is 'open on a specific tab'."],"exampleFix":"// before\n$spreadsheet->setFirstSheetIndex($selected - 1); // throws when $selected === 0\n\n// after\n$spreadsheet->setFirstSheetIndex(max(0, $selected - 1));","handlingStrategy":"validation","validationCode":"$max = $spreadsheet->getSheetCount() - 1;\n$spreadsheet->setFirstSheetIndex(max(0, min($firstSheetIndex, $max)));","typeGuard":"function isValidFirstSheetIndex(\\PhpOffice\\PhpSpreadsheet\\Spreadsheet $s, int $i): bool\n{\n    return $i >= 0;\n}","tryCatchPattern":"try {\n    $spreadsheet->setFirstSheetIndex($index);\n} catch (\\PhpOffice\\PhpSpreadsheet\\Exception $e) {\n    $spreadsheet->setFirstSheetIndex(0);\n}","preventionTips":["Map 'none' sentinels (-1, null) to 0 before calling.","Clamp computed indexes with max(0, ...).","Remember the API is 0-based and accepts 0."],"tags":["workbook-view","validation","first-sheet-index","phpspreadsheet"],"backgroundTag":"value-out-of-range","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}