Tencent/matrix · error · ProcStatUtil.ParseException

Can only rewind one step!

Error message

Can only rewind one step!

What it means

ProcStatReader.rewind() steps the lexer back exactly one character; it guards with mRewound so two rewinds cannot happen without an intervening read. Throwing 'Can only rewind one step!' means the internal lexer invariant was violated - a second rewind was requested while one was already pending.

Solutions

  1. Check the /proc/<pid>/stat content on the failing device for unexpected formatting (e.g. unusual process names) and report/adjust the parsing assumptions.
  2. Catch ParseException and fall back to ProcStatUtil.parseWithBuffer, which parses from a raw byte buffer.
  3. Ensure field-extraction helpers consume at least one valid character before rewinding; avoid calling skipPast/readWord on adjacent delimiters.
  4. Update the Matrix version - newer releases harden proc stat parsing for edge-case formats.
Defensive patterns

Strategy: try-catch

Try / catch

try { CharBuffer w = reader.readWord(); } catch (ProcStatUtil.ParseException e) { reader.close(); reader = new ProcStatReader(path); }

Prevention

When it happens

Trigger: A token-reading helper (readWord/readNumber/readToSymbol/skipPast) hits a non-matching character on the very first character it consumes and then again on a subsequent first-character mismatch, causing rewind() to be invoked twice without advancing.

Common situations: Malformed or unexpected /proc stat content where consecutive delimiters (e.g. a comm field not wrapped in parentheses, or two adjacent spaces) break the assumed token layout; usually indicates a kernel format the parser did not anticipate.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of Tencent/matrix@3b8293bd65 (2026-09-08). Data as JSON: /api/errors/c0eb1da934fec5ea. Report an issue: GitHub.

Appendix: source

Thrown at matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/ProcStatReader.java:119

    public boolean hasReachedEOF() {
        return mBufferSize == -1;
    }

    private void next() {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }

        mPosition++;
        mPrev = mChar;
        mChar = (char) mBuffer[mPosition];

        mRewound = false;
    }

    private void rewind() {
        if (mRewound) {
            throw new ParseException("Can only rewind one step!");
        }

        mPosition--;
        mChar = mPrev;
        mRewound = true;
    }


    public CharBuffer readWord(CharBuffer buffer) {
        buffer.clear();

        boolean isFirstRun = true;

        while (hasNext()) {
            next();
            if (!Character.isWhitespace(mChar)) {
                if (!buffer.hasRemaining()) {
                    CharBuffer newBuffer = CharBuffer.allocate(buffer.capacity() * 2);

View on GitHub (pinned to 3b8293bd65)