{"record":{"id":"008d852d7a2aed3e","repo":"Tencent/matrix","slug":"couldn-t-read-string","errorCode":null,"errorMessage":"Couldn't read string!","messagePattern":"Couldn't read string!","errorType":"exception","errorClass":"ProcStatUtil.ParseException","httpStatus":null,"severity":"error","filePath":"matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/ProcStatReader.java","lineNumber":145,"sourceCode":"\n    public CharBuffer readWord(CharBuffer buffer) {\n        buffer.clear();\n\n        boolean isFirstRun = true;\n\n        while (hasNext()) {\n            next();\n            if (!Character.isWhitespace(mChar)) {\n                if (!buffer.hasRemaining()) {\n                    CharBuffer newBuffer = CharBuffer.allocate(buffer.capacity() * 2);\n                    buffer.flip();\n                    newBuffer.put(buffer);\n                    buffer = newBuffer;\n                }\n\n                buffer.put(mChar);\n            } else if (isFirstRun) {\n                throw new ParseException(\"Couldn't read string!\");\n            } else {\n                rewind();\n                break;\n            }\n\n            isFirstRun = false;\n        }\n\n        if (isFirstRun) {\n            throw new ParseException(\"Couldn't read string because file ended!\");\n        }\n\n        buffer.flip();\n        return buffer;\n    }\n\n    public long readNumber() {\n        long sign = 1;","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/Tencent/matrix/blob/3b8293bd65d47eeea7caf1f32a3a5d4d5eab60e7/matrix/matrix-android/matrix-battery-canary/src/main/java/com/tencent/matrix/batterycanary/utils/ProcStatReader.java#L127-L163","documentation":"ProcStatReader.readWord() builds a whitespace-delimited token; if the very first character it reads is not a valid word character it cannot form any token and throws ParseException(\"Couldn't read string!\"). This means the lexer found an unexpected character where a token was expected.","triggerScenarios":"Calling state() (which uses readWord) when the current stream position starts on a character that fails the word-character predicate on the first iteration (isFirstRun).","commonSituations":"Peculiar /proc stat formatting on some kernels or emulators where the expected field is missing, empty, or preceded by unexpected characters; misaligned field offsets after a prior parse error.","solutions":["Catch ParseException in the caller and skip this sample tick; proc stat anomalies are usually transient.","Inspect the actual /proc/<pid>/stat content on the failing device and validate it before parsing.","Switch to ProcStatUtil.parseWithBuffer (byte-buffer based) which handles the parenthesized comm field differently.","Retry on the next poll; a republished process or new tick typically parses fine."],"exampleFix":"// before\nCharBuffer word = reader.state();\n// after\nCharBuffer word;\ntry {\n    word = reader.state();\n} catch (ProcStatUtil.ParseException e) {\n    return null; // skip malformed stat sample\n}","handlingStrategy":"try-catch","validationCode":"byte[] head = readFirstBytes(\"/proc/\" + pid + \"/stat\", 64);\nif (head == null || head.length == 0) { /* skip pid */ }","typeGuard":null,"tryCatchPattern":"try { CharBuffer w = reader.state(); } catch (ProcStatUtil.ParseException e) { return null; }","preventionTips":["Skip pids whose stat file is empty or unreadable","Retry on the next tick rather than reusing a failed reader","Validate raw stat format once on new device models","Fall back to parseWithBuffer"],"tags":["android","proc-stat","parser"],"backgroundTag":"file-read-failed","analyzedSha":"3b8293bd65d47eeea7caf1f32a3a5d4d5eab60e7","analyzedAt":"2026-09-08T08:01:39.722Z","contentChangedAt":"2026-09-08T08:01:39.722Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}