nostra13/Android-Universal-Image-Loader · error · IOException
LineReader is closed
Error message
LineReader is closed
What it means
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.
Source
Thrown at library/src/main/java/com/nostra13/universalimageloader/cache/disc/impl/ext/StrictLineReader.java:127
if (buf != null) {
buf = null;
in.close();
}
}
}
/**
* Reads the next line. A line ends with {@code "\n"} or {@code "\r\n"},
* this end of line marker is not included in the result.
*
* @return the next line from the input.
* @throws IOException for underlying {@code InputStream} errors.
* @throws EOFException for the end of source stream.
*/
public String readLine() throws IOException {
synchronized (in) {
if (buf == null) {
throw new IOException("LineReader is closed");
}
// Read more data if we are at the end of the buffered data.
// Though it's an error to read after an exception, we will let {@code fillBuf()}
// throw again if that happens; thus we need to handle end == -1 as well as end == pos.
if (pos >= end) {
fillBuf();
}
// Try to find LF in the buffered data and return the line if successful.
for (int i = pos; i != end; ++i) {
if (buf[i] == LF) {
int lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i;
String res = new String(buf, pos, lineEnd - pos, charset.name());
pos = i + 1;
return res;
}
}
View on GitHub (pinned to ba33ec64d0)
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.
Example fix
// before
try {
while (true) parse(reader.readLine());
} catch (EOFException e) {
reader.close();
}
handle(reader.readLine()); // use after close
// after
try {
while (true) parse(reader.readLine());
} catch (EOFException e) {
// end of journal: stop reading
} finally {
reader.close();
} Defensive patterns
Strategy: try-catch
Try / catch
try {
while (true) { line = reader.readLine(); process(line); }
} catch (EOFException done) {
// normal end of stream — stop, do not read again
} finally {
Util.closeQuietly(reader); // single close point
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- cache is closed
- capacity <= 0
- Unsupported encoding
- unexpected journal header: [{magic}, {version}, {valueCountS
- unexpected journal line: {line}
AI-assisted analysis of nostra13/Android-Universal-Image-Loader@ba33ec64d0 (2026-08-14).
Data as JSON: /api/errors/ea0394302ec8f387.
Report an issue: GitHub.