{"record":{"id":"4aadd89966958162","repo":"antlr/antlr4","slug":"cannot-consume-eof-4aadd8","errorCode":null,"errorMessage":"cannot consume EOF","messagePattern":"cannot consume EOF","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"runtime/CSharp/src/UnbufferedCharStream.cs","lineNumber":156,"sourceCode":"        {\n            this.input = new StreamReader(input);\n            Fill(1);\n        }\n\n        public UnbufferedCharStream(TextReader input, int bufferSize)\n            : this(bufferSize)\n        {\n            // prime\n            this.input = input;\n            Fill(1);\n        }\n\n        // prime\n        public virtual void Consume()\n        {\n            if (LA(1) == IntStreamConstants.EOF)\n            {\n                throw new InvalidOperationException(\"cannot consume EOF\");\n            }\n            // buf always has at least data[p==0] in this method due to ctor\n            lastChar = data[p];\n            // track last char for LA(-1)\n            if (p == n - 1 && numMarkers == 0)\n            {\n                n = 0;\n                p = -1;\n                // p++ will leave this at 0\n                lastCharBufferStart = lastChar;\n            }\n            p++;\n            currentCharIndex++;\n            Sync(1);\n        }\n\n        /// <summary>\n        /// Make sure we have 'need' elements from current position","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/CSharp/src/UnbufferedCharStream.cs#L138-L174","documentation":"UnbufferedCharStream is a forward-only character input. Consume() is illegal once LA(1) is EOF because there is no character left to consume. This guard protects the stream invariant that consumption only happens while real input remains.","triggerScenarios":"User code manually calls charStream.Consume() after already reading to EOF; a custom lexer or test loop consumes without checking LA(1); or the same stream is exhausted by one consumer and then consumed again.","commonSituations":"Hand-written tokenizing loops; harnesses that call Consume() an input-length number of times plus one; reusing an UnbufferedCharStream after a previous parse; or custom ICharStream adapters with incorrect EOF behavior.","solutions":["Check LA(1) != IntStreamConstants.EOF before every Consume().","Use a fresh stream for each parse.","Audit custom code that drives Consume() and ensure it stops at EOF.","If random access or repeated parsing is required, use AntlrInputStream with fully buffered input."],"exampleFix":"// before\nstream.Consume();\n\n// after\nif (stream.LA(1) != IntStreamConstants.EOF)\n    stream.Consume();","handlingStrategy":"validation","validationCode":"if (stream.LA(1) != IntStreamConstants.EOF)\n    stream.Consume();","typeGuard":null,"tryCatchPattern":"try { stream.Consume(); }\ncatch (InvalidOperationException ex) when (ex.Message == \"cannot consume EOF\") { /* stop consuming */ }","preventionTips":["Make EOF a loop-exit condition, not a consumable value.","Never reuse an exhausted unbuffered stream.","Prefer parser/lexer-driven consumption over manual loops."],"tags":["antlr","csharp","char-stream","eof","streaming"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}