{"record":{"id":"cd36f378d02f2a09","repo":"antlr/antlr4","slug":"token-index-i-out-of-range-0-tokens-count-1","errorCode":null,"errorMessage":"token index {i} out of range 0..{tokens.Count - 1}","messagePattern":"token index (.+?) out of range 0\\.\\.(.+?)","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"runtime/CSharp/src/BufferedTokenStream.cs","lineNumber":259,"sourceCode":"                if (t is IWritableToken)\n                {\n                    ((IWritableToken)t).TokenIndex = tokens.Count;\n                }\n                tokens.Add(t);\n                if (t.Type == TokenConstants.EOF)\n                {\n                    fetchedEOF = true;\n                    return i + 1;\n                }\n            }\n            return n;\n        }\n\n        public virtual IToken Get(int i)\n        {\n            if (i < 0 || i >= tokens.Count)\n            {\n                throw new ArgumentOutOfRangeException(\"token index \" + i + \" out of range 0..\" + (tokens.Count - 1));\n            }\n            return tokens[i];\n        }\n\n        /// <summary>Get all tokens from start..stop inclusively.</summary>\n        /// <remarks>Get all tokens from start..stop inclusively.</remarks>\n        public virtual IList<IToken> Get(int start, int stop)\n        {\n            if (start < 0 || stop < 0)\n            {\n                return null;\n            }\n            LazyInit();\n            IList<IToken> subset = new List<IToken>();\n            if (stop >= tokens.Count)\n            {\n                stop = tokens.Count - 1;\n            }","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/CSharp/src/BufferedTokenStream.cs#L241-L277","documentation":"BufferedTokenStream.Get(int i) does random access into the buffered token list and requires 0 <= i < tokens.Count. Unlike LA/LT, which fetch lazily, Get only sees tokens already buffered, so an index that looks valid for the source may still be out of range if the stream has not been fetched that far. The exception message reports the offending index and the valid 0..Count-1 range.","triggerScenarios":"Calling Get(i) with a negative index, an index >= tokens.Count (e.g. using LT(k).TokenIndex from a further position, or computing stopIndex+1 after a rule), or assuming Get fetches on demand like LA does.","commonSituations":"Error-reporting code that walks token context by absolute index without bounds checks; using Get(Size()) to look for a token past the end; mixing relative lookahead offsets (k) with absolute indices when calling Get.","solutions":["Clamp the index: if (i >= 0 && i < stream.Size) token = stream.Get(i)","Prefer LT(k)/LA(k) for lookahead and Get(TokenIndex) only with indices taken from real tokens","Call stream.Size (which forces fetching up to EOF) before doing index math if you need the full count"],"exampleFix":"// before\nIToken tok = stream.Get(stopIndex + 1); // may be out of range\n\n// after\nIToken tok = stopIndex + 1 < stream.Size ? stream.Get(stopIndex + 1) : stream.Get(stream.Size - 1);","handlingStrategy":"validation","validationCode":"IToken t = i >= 0 && i < stream.Size ? stream.Get(i) : null;","typeGuard":null,"tryCatchPattern":"try { tok = stream.Get(i); } catch (ArgumentOutOfRangeException) { tok = null; /* index beyond buffer */ }","preventionTips":["Use stream.Size as the authoritative upper bound for index math","Prefer LT(k) for lookahead; reserve Get(i) for indices taken from real tokens"],"tags":["antlr","csharp","token-stream","index-out-of-range"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}