antlr/antlr4 · error · ArgumentException

cannot seek to negative index ${index}

Error message

cannot seek to negative index ${index}

What it means

UnbufferedCharStream keeps only a rolling window of already unread data. Seek() maps the requested absolute index to a buffer offset; a negative offset means the position was discarded and cannot be restored. Backward seeks are therefore illegal once the needed data has left the buffer.

Source

Thrown at runtime/CSharp/src/UnbufferedCharStream.cs:385

        /// <c>index-bufferStartIndex</c>
        /// .
        /// </remarks>
        public virtual void Seek(int index)
        {
            if (index == currentCharIndex)
            {
                return;
            }
            if (index > currentCharIndex)
            {
                Sync(index - currentCharIndex);
                index = Math.Min(index, BufferStartIndex + n - 1);
            }
            // index == to bufferStartIndex should set p to 0
            int i = index - BufferStartIndex;
            if (i < 0)
            {
                throw new ArgumentException("cannot seek to negative index " + index);
            }
            else
            {
                if (i >= n)
                {
                    throw new NotSupportedException("seek to index outside buffer: " + index + " not in " + BufferStartIndex + ".." + (BufferStartIndex + n));
                }
            }
            p = i;
            currentCharIndex = index;
            if (p == 0)
            {
                lastChar = lastCharBufferStart;
            }
            else
            {
                lastChar = data[p - 1];
            }

View on GitHub (pinned to 7d5770395b)

Solutions

  1. Do not seek backward on UnbufferedCharStream; process input in one forward pass.
  2. Keep a Mark() active for any earlier position that must remain seekable and release it only after seeking is complete.
  3. Use AntlrInputStream (fully buffered characters) when backward seeks are required.

Example fix

// before
var chars = new UnbufferedCharStream(reader, 4096);
chars.Seek(0);

// after
var chars = new AntlrInputStream(reader); // supports random access
chars.Seek(0);
Defensive patterns

Strategy: validation

Validate before calling

if (targetIndex < chars.Index && randomAccessRequired)
    chars = new AntlrInputStream(reader); // or retain a Mark()

Type guard

static bool SupportsBackwardSeek(ICharStream stream) => stream is not UnbufferedCharStream;

Try / catch

try { chars.Seek(index); }
catch (ArgumentException ex) when (ex.Message.StartsWith("cannot seek to negative index")) { /* use buffered stream or keep markers */ }

Prevention

When it happens

Trigger: Calling Seek(oldIndex) after consuming beyond the retained window; releasing the marker that protected old data and then seeking back; or custom code assuming ICharStream supports arbitrary random access.

Common situations: Backtracking or reset logic is used with an unbuffered stream; a parser strategy requires rewinding; or migration from AntlrInputStream/CommonTokenStream to UnbufferedCharStream without preserving markers.

Related errors


AI-assisted analysis of antlr/antlr4@7d5770395b (2026-08-14). Data as JSON: /api/errors/ec754a17802d6c10. Report an issue: GitHub.