Tencent/matrix · warning · ParseException

cutime

Error message

${statBuffer}
cutime: ${num}

What it means

ProcStatUtil parses the kernel /proc/<pid>/stat format field-by-field; field 16 (cutime, waited-for children's user time) must be numeric. When the token read for field 16 fails isNumeric(), it throws java.text.ParseException carrying the full raw stat buffer plus the offending token, so callers can see exactly which field of the proc entry was malformed.

Solutions

  1. Wrap the parse call in try-catch (ParseException) and skip/retry the sample instead of crashing battery monitoring.
  2. Check the raw stat string in the exception message: verify field 16 (cutime) is an integer; recount fields after the '(comm)' section since spaces in comm shift the index.
  3. Re-read /proc/<pid>/stat fresh — a torn/truncated read is the usual cause; retry usually succeeds.
  4. If it reproduces on one device, dump the kernel version and compare /proc/self/stat output; consider falling back to parseWithSplits or disabling the collector on that ROM.

Example fix

// before
ProcStat stat = ProcStatUtil.parseWithBufferForPath(path);
// after
ProcStat stat;
try {
    stat = ProcStatUtil.parseWithBufferForPath(path);
} catch (ParseException e) {
    MatrixLog.w(TAG, "bad stat: " + e.getMessage());
    stat = null; // skip this sample
}
Defensive patterns

Strategy: try-catch

Validate before calling

String raw = readProcStat(pid);
if (raw != null && raw.contains(")") && raw.split("\\s+").length >= 22) {
    stat = ProcStatUtil.parseWithBufferForPath(path);
}

Type guard

static boolean looksLikeValidStat(String raw) {
    if (raw == null || raw.indexOf(')') < 0) return false;
    String[] parts = raw.split("\\s+");
    return parts.length >= 22 && parts[16].matches("\\d+") && parts[17].matches("\\d+");
}

Try / catch

try {
    stat = ProcStatUtil.parseWithBufferForPath(path);
} catch (ParseException e) {
    Log.w(TAG, "stat parse failed, skipping sample: " + e.getMessage());
    stat = null;
}

Prevention

When it happens

Trigger: Calling ProcStatUtil.parseWithBuffer (via parseWithBufferForPath) on a /proc stat byte buffer whose field 16 does not parse as a number — e.g. truncated/partial read of /proc/<tid>/stat, a process exiting mid-read leaving a torn line, or kernel/vendor formats that shift field positions (comm containing unexpected bytes breaking field indexing).

Common situations: Reading stat of a thread/process that dies between open and read on a heavily loaded device; OEM kernels with modified /proc formatting; parsing stale buffers captured at app start when the process table is churning.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

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

                        window++;
                    }
                    String num = safeBytesToString(statBuffer, readIdx, window);
                    if (!isNumeric(num)) {
                        throw new ParseException(safeBytesToString(statBuffer, 0, statBuffer.length) + "\nstime: " + num);
                    }
                    stat.stime = MatrixUtil.parseLong(num, 0);
                    break;
                }
                case 16: { // cutime
                    int readIdx = i, window = 0;
                    // seek next space
                    while (i < statBytes && !Character.isSpaceChar(statBuffer[i])) {
                        i++;
                        window++;
                    }
                    String num = safeBytesToString(statBuffer, readIdx, window);
                    if (!isNumeric(num)) {
                        throw new ParseException(safeBytesToString(statBuffer, 0, statBuffer.length) + "\ncutime: " + num);
                    }
                    stat.cutime = MatrixUtil.parseLong(num, 0);
                    break;
                }
                case 17: { // cstime
                    int readIdx = i, window = 0;
                    // seek next space
                    while (i < statBytes && !Character.isSpaceChar(statBuffer[i])) {
                        i++;
                        window++;
                    }
                    String num = safeBytesToString(statBuffer, readIdx, window);
                    if (!isNumeric(num)) {
                        throw new ParseException(safeBytesToString(statBuffer, 0, statBuffer.length) + "\ncstime: " + num);
                    }
                    stat.cstime = MatrixUtil.parseLong(num, 0);
                    break;
                }

View on GitHub (pinned to 3b8293bd65)