{"record":{"id":"51bd90e8395061d7","repo":"sebastianbergmann/php-token-stream","slug":"no-token-at-position-s","errorCode":null,"errorMessage":"No token at position \"%s\"","messagePattern":"No token at position \"(.+?)\"","errorType":"exception","errorClass":"OutOfBoundsException","httpStatus":null,"severity":"error","filePath":"src/Stream.php","lineNumber":348,"sourceCode":"    /**\n     * @param int $offset\n     *\n     * @return bool\n     */\n    public function offsetExists($offset)\n    {\n        return isset($this->tokens[$offset]);\n    }\n\n    /**\n     * @param int $offset\n     *\n     * @throws OutOfBoundsException\n     */\n    public function offsetGet($offset)\n    {\n        if (!$this->offsetExists($offset)) {\n            throw new OutOfBoundsException(\n                \\sprintf(\n                    'No token at position \"%s\"',\n                    $offset\n                )\n            );\n        }\n\n        return $this->tokens[$offset];\n    }\n\n    /**\n     * @param int $offset\n     */\n    public function offsetSet($offset, $value)/*: void*/\n    {\n        $this->tokens[$offset] = $value;\n    }\n","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/sebastianbergmann/php-token-stream/blob/76fc0567751d177847112bd3e26e4890529c98da/src/Stream.php#L330-L366","documentation":"PHP_Token_Stream implements ArrayAccess, so `$stream[$offset]` reads a token by its integer index in the tokenized source. offsetGet() first checks offsetExists() (isset on the internal tokens array); if the offset does not exist it throws OutOfBoundsException with the requested position. The library treats out-of-range access on a token stream as an out-of-bounds read, consistent with SeekableIterator semantics.","triggerScenarios":"Reading `$stream[$i]` (or offsetGet($i) directly) where $i < 0, $i >= count($stream), or where the stream was built from empty source so no token exists at that index. Also occurs when iterating past the end or when stale indices from a previous tokenization are reused after the file changed.","commonSituations":"Looping `for ($i = 0; $i <= count($stream); $i++)` with an off-by-one `<=`; caching token indices across edits to the analyzed file; assuming index 0 exists when the file is empty or contains only whitespace; code that mixes line numbers with token indices and reads the wrong array.","solutions":["Check the offset before access: only read `$stream[$i]` when `$i >= 0 && $i < count($stream)` (or `isset($stream[$i])`).","Fix off-by-one loop bounds (`<` instead of `<=`) against the stream's count().","If the stream may be empty, handle that case explicitly before indexing.","Re-instantiate PHP_Token_Stream if the underlying file changed after indices were computed, instead of reusing old indices.","If the access is intentional optional probing, wrap in try/catch OutOfBoundsException or use isset() rather than offsetGet()."],"exampleFix":"// before\nfor ($i = 0; $i <= count($stream); $i++) {\n    $token = $stream[$i]; // OutOfBoundsException on last iteration\n}\n// after\n$count = count($stream);\nfor ($i = 0; $i < $count; $i++) {\n    $token = $stream[$i];\n}","handlingStrategy":"type-guard","validationCode":"// PHP\nfunction tokenAt(PHP_Token_Stream $stream, int $index): ?PHP_Token {\n    return ($index >= 0 && $index < count($stream)) ? $stream[$index] : null;\n}","typeGuard":"function hasTokenAt(PHP_Token_Stream $stream, int $index): bool {\n    return $index >= 0 && $index < count($stream);\n}","tryCatchPattern":"try {\n    $token = $stream[$index];\n} catch (\\OutOfBoundsException $e) {\n    // no token at this position; handle absence (skip/log/fallback)\n    $token = null;\n}","preventionTips":["Always bound loops with `count($stream)` and strict `<`, never `<=`.","Prefer `isset($stream[$i])` for optional probing instead of direct access.","Never reuse token indices after the source file changes; re-tokenize.","Distinguish token indices from line numbers and from raw token_get_all() offsets."],"tags":["php","arrayaccess","out-of-bounds","tokenizer"],"backgroundTag":"index-out-of-bounds","analyzedSha":"76fc0567751d177847112bd3e26e4890529c98da","analyzedAt":"2026-09-16T03:15:47.562Z","contentChangedAt":"2026-09-16T03:15:47.562Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}