Tencent/matrix · warning · ProcStatUtil.ParseException

Couldn't read number because the file ended!

Error message

Couldn't read number because the file ended!

What it means

ProcStatReader.readNumber() throws ParseException("Couldn't read number because the file ended!") when EOF is hit before any digit is consumed (isFirstRun still true). The numeric field the parser requested does not exist in the stream.

Solutions

  1. Treat this as process-exit: catch ParseException, remove the pid from tracking, and stop sampling it.
  2. Check /proc/<pid> existence immediately before parsing to narrow the race window.
  3. Retry on the next tick with a freshly opened reader; do not reuse a reader positioned at EOF.
  4. Log the pid and tick so persistent failures for one pid can be detected and dropped.

Example fix

// before
long jiffy = ProcStatUtil.instance.jiffies(pid, true);
// after
try {
    long jiffy = ProcStatUtil.instance.jiffies(pid, true);
} catch (ProcStatUtil.ParseException e) {
    mWatchingPids.remove(pid); // process ended
}
Defensive patterns

Strategy: retry

Validate before calling

java.io.File f = new File("/proc/" + pid + "/stat");
if (!f.exists() || f.length() < 16) { /* skip: likely dead process */ }

Try / catch

try { ... } catch (ProcStatUtil.ParseException e) { /* EOF: treat as process exit, remove pid */ }

Prevention

When it happens

Trigger: Calling jiffies()/readNumber at the end of /proc/<pid>/stat - the file was truncated or the process exited while reading, so utime/stime are absent.

Common situations: Race between checking the pid and reading its stat file; very short-lived threads terminating during battery sampling.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

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

            next();
            if (Character.isDigit(mChar)) {
                result = result * 10 + (mChar - '0');
            } else if (isFirstRun) {
                if (mChar == '-') {
                    sign = -1;
                } else {
                    throw new ParseException("Couldn't read number!");
                }
            } else {
                rewind();
                break;
            }

            isFirstRun = false;
        }

        if (isFirstRun) {
            throw new ParseException("Couldn't read number because the file ended!");
        }

        return sign * result;
    }

    public CharBuffer readToSymbol(char symbol, CharBuffer buffer) {
        buffer.clear();
        boolean isFirstRun = true;

        while (hasNext()) {
            next();
            if (symbol != mChar) {
                if (!buffer.hasRemaining()) {
                    CharBuffer newBuffer = CharBuffer.allocate(buffer.capacity() * 2);
                    buffer.flip();
                    newBuffer.put(buffer);
                    buffer = newBuffer;
                }

View on GitHub (pinned to 3b8293bd65)