{"record":{"id":"ea0394302ec8f387","repo":"nostra13/Android-Universal-Image-Loader","slug":"linereader-is-closed","errorCode":null,"errorMessage":"LineReader is closed","messagePattern":"LineReader is closed","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"library/src/main/java/com/nostra13/universalimageloader/cache/disc/impl/ext/StrictLineReader.java","lineNumber":127,"sourceCode":"\t\t\tif (buf != null) {\n\t\t\t\tbuf = null;\n\t\t\t\tin.close();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Reads the next line. A line ends with {@code \"\\n\"} or {@code \"\\r\\n\"},\n\t * this end of line marker is not included in the result.\n\t *\n\t * @return the next line from the input.\n\t * @throws IOException for underlying {@code InputStream} errors.\n\t * @throws EOFException for the end of source stream.\n\t */\n\tpublic String readLine() throws IOException {\n\t\tsynchronized (in) {\n\t\t\tif (buf == null) {\n\t\t\t\tthrow new IOException(\"LineReader is closed\");\n\t\t\t}\n\n\t\t\t// Read more data if we are at the end of the buffered data.\n\t\t\t// Though it's an error to read after an exception, we will let {@code fillBuf()}\n\t\t\t// throw again if that happens; thus we need to handle end == -1 as well as end == pos.\n\t\t\tif (pos >= end) {\n\t\t\t\tfillBuf();\n\t\t\t}\n\t\t\t// Try to find LF in the buffered data and return the line if successful.\n\t\t\tfor (int i = pos; i != end; ++i) {\n\t\t\t\tif (buf[i] == LF) {\n\t\t\t\t\tint lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i;\n\t\t\t\t\tString res = new String(buf, pos, lineEnd - pos, charset.name());\n\t\t\t\t\tpos = i + 1;\n\t\t\t\t\treturn res;\n\t\t\t\t}\n\t\t\t}\n","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/nostra13/Android-Universal-Image-Loader/blob/ba33ec64d0daaa881d35852460e78c58d086bc18/library/src/main/java/com/nostra13/universalimageloader/cache/disc/impl/ext/StrictLineReader.java#L109-L145","documentation":"StrictLineReader.readLine throws IOException('LineReader is closed') after close() has been called — the close path nulls the internal buffer, and subsequent reads detect it. This is a use-after-close lifecycle error, not data corruption, and surfaces during journal replay or writing in DiskLruCache when a reader is reused after being closed.","triggerScenarios":"Calling readLine() after close(); in-library, typically via an error path where the reader/stream was closed in a finally block but the read loop continued, or two threads sharing one StrictLineReader where one closes it. The internal readLine is synchronized on the underlying stream, so cross-thread close-after-read races are the realistic producer.","commonSituations":"Custom code built on StrictLineReader with mismatched try/finally scoping; concurrent close during parsing (e.g. shutdown thread closing the cache while open() is still replaying the journal); adapted code that catches EOFException, closes, then accidentally reads once more.","solutions":["Scope reads strictly inside the reader's lifetime: read inside try, close in the single finally, and never touch the reader afterwards.","On EOFException, break the loop immediately — do not read again after the stream ends.","Restrict each StrictLineReader to one thread/one owner; no shared readers."],"exampleFix":"// before\ntry {\n    while (true) parse(reader.readLine());\n} catch (EOFException e) {\n    reader.close();\n}\nhandle(reader.readLine()); // use after close\n\n// after\ntry {\n    while (true) parse(reader.readLine());\n} catch (EOFException e) {\n    // end of journal: stop reading\n} finally {\n    reader.close();\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    while (true) { line = reader.readLine(); process(line); }\n} catch (EOFException done) {\n    // normal end of stream — stop, do not read again\n} finally {\n    Util.closeQuietly(reader); // single close point\n}","preventionTips":["One owner, one lifetime: open -> read -> close in a single scoped block; never read after finally.","On EOFException, exit the read loop immediately.","Do not share StrictLineReader instances across threads; close comes from the owning thread."],"tags":["io","lifecycle","use-after-close","concurrency","utility"],"backgroundTag":null,"analyzedSha":"ba33ec64d0daaa881d35852460e78c58d086bc18","analyzedAt":"2026-08-14T15:41:15.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}