{"record":{"id":"27e937770d25a790","repo":"PHPOffice/PhpSpreadsheet","slug":"token-with-id-id-does-not-exist","errorCode":null,"errorMessage":"Token with id $id does not exist.","messagePattern":"Token with id \\$id does not exist\\.","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Calculation\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Calculation/FormulaParser.php","lineNumber":99,"sourceCode":"     * Get Formula.\n     */\n    public function getFormula(): string\n    {\n        return $this->formula;\n    }\n\n    /**\n     * Get Token.\n     *\n     * @param int $id Token id\n     */\n    public function getToken(int $id = 0): FormulaToken\n    {\n        if (isset($this->tokens[$id])) {\n            return $this->tokens[$id];\n        }\n\n        throw new Exception(\"Token with id $id does not exist.\");\n    }\n\n    /**\n     * Get Token count.\n     */\n    public function getTokenCount(): int\n    {\n        return count($this->tokens);\n    }\n\n    /**\n     * Get Tokens.\n     *\n     * @return FormulaToken[]\n     */\n    public function getTokens(): array\n    {\n        return $this->tokens;","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Calculation/FormulaParser.php#L81-L117","documentation":"FormulaParser::getToken(int $id) indexes the token list built by parseToTokens(); an out-of-range id throws Calculation\\Exception with 'Token with id $id does not exist.' An empty or whitespace-only formula yields zero tokens, so even getToken(0) with the default id can throw. The exception is a plain PHP exception, not an Excel error value.","triggerScenarios":"Off-by-one loop: for ($i = 0; $i <= $parser->getTokenCount(); $i++) - the last iteration is out of range; calling getToken() on a parser constructed with ''; keeping a token index across a re-parse of a different formula.","commonSituations":"Walking tokens to rewrite formulas (bulk reference rewriting); token-stream analysis tooling; processing migrated sheets where some cells contain empty formula strings.","solutions":["Bound the loop with $i < $parser->getTokenCount()","Iterate getTokens() directly instead of indexing by id","Early-return when getTokenCount() === 0","Recompute indexes whenever the parsed formula changes"],"exampleFix":"// before\nfor ($i = 0; $i <= $parser->getTokenCount(); $i++) { // off-by-one: last id does not exist\n    process($parser->getToken($i));\n}\n\n// after\n$count = $parser->getTokenCount();\nfor ($i = 0; $i < $count; $i++) {\n    process($parser->getToken($i));\n}","handlingStrategy":"validation","validationCode":"$count = $parser->getTokenCount();\nif ($count === 0) {\n    return; // nothing to walk\n}\nfor ($i = 0; $i < $count; $i++) {\n    $token = $parser->getToken($i);\n}","typeGuard":"function tokenExists(FormulaParser $parser, int $id): bool\n{\n    return $id >= 0 && $id < $parser->getTokenCount();\n}","tryCatchPattern":"try {\n    $token = $parser->getToken($id);\n} catch (\\PhpOffice\\PhpSpreadsheet\\Calculation\\Exception $e) {\n    // 'Token with id N does not exist.' - fix the index bound, do not retry\n}","preventionTips":["Prefer iterating getTokens() over index-based access","Treat getTokenCount() as an exclusive upper bound","Guard the empty-formula case (0 tokens) before accessing getToken(0)"],"tags":["phpspreadsheet","php","excel","formula-parser","index-out-of-bounds","off-by-one"],"backgroundTag":"index-out-of-bounds","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}