{"record":{"id":"754daca4f1a00b5a","repo":"antlr/antlr4","slug":"lt-i-gives-negative-index-754dac","errorCode":null,"errorMessage":"LT(${i}) gives negative index","messagePattern":"LT\\((.+?)\\) gives negative index","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"runtime/CSharp/src/UnbufferedTokenStream.cs","lineNumber":137,"sourceCode":"            int bufferStartIndex = GetBufferStartIndex();\n            if (i < bufferStartIndex || i >= bufferStartIndex + n)\n            {\n                throw new ArgumentOutOfRangeException(\"get(\" + i + \") outside buffer: \" + bufferStartIndex + \"..\" + (bufferStartIndex + n));\n            }\n            return tokens[i - bufferStartIndex];\n        }\n\n        public virtual IToken LT(int i)\n        {\n            if (i == -1)\n            {\n                return lastToken;\n            }\n            Sync(i);\n            int index = p + i - 1;\n            if (index < 0)\n            {\n                throw new ArgumentOutOfRangeException(\"LT(\" + i + \") gives negative index\");\n            }\n            if (index >= n)\n            {\n                System.Diagnostics.Debug.Assert(n > 0 && tokens[n - 1].Type == TokenConstants.EOF);\n                return tokens[n - 1];\n            }\n            return tokens[index];\n        }\n\n        public virtual int LA(int i)\n        {\n            return LT(i).Type;\n        }\n\n        public virtual ITokenSource TokenSource\n        {\n            get\n            {","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/CSharp/src/UnbufferedTokenStream.cs#L119-L155","documentation":"LT(i) maps positive lookahead to index p+i-1, and only i == -1 is special-cased to return the previous token. If the computed index is negative, the request looks before the beginning of the available token stream and is rejected. LT(0) and lookahead values below -1 are the usual causes.","triggerScenarios":"Calling LT(0) at the start of the stream; calling LT(-2) or smaller; generic loops that call LT(i) beginning at zero; or code that assumes LT(0) returns the current token or null.","commonSituations":"Token-iteration helpers written for a different API; lookahead loops using inclusive zero-based indexes; porting from another runtime whose LT semantics differ.","solutions":["Use LT(1) for the current lookahead token and LT(-1) for the previous token.","Do not call LT(0).","Ensure lookahead loops start at i = 1."],"exampleFix":"// before\nIToken current = tokens.LT(0);\n\n// after\nIToken current = tokens.LT(1);","handlingStrategy":"validation","validationCode":"if (i != -1 && i < 1)\n    throw new ArgumentOutOfRangeException(nameof(i), \"Use LT(1) or LT(-1).\");\nvar token = tokens.LT(i);","typeGuard":null,"tryCatchPattern":"try { var t = tokens.LT(i); }\ncatch (ArgumentOutOfRangeException ex) when (ex.Message.StartsWith(\"LT(\")) { /* correct lookahead index */ }","preventionTips":["Start lookahead loops at 1.","Use LT(-1) only for the immediately preceding token.","Do not assume LT(0) exists."],"tags":["antlr","csharp","token-stream","lookahead","input-validation"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}