HMCL-dev/HMCL · error · PngException
ERROR_EOF_EXPECTED
ERROR_EOF_EXPECTED
Error message
Completed IEND but %d byte(s) remain
What it means
A conformant PNG stream ends at the IEND chunk; any bytes after IEND are unexpected trailing data. After the chunk loop finishes, PngReadHelper.read checks source.available() and throws PngException with code ERROR_EOF_EXPECTED when leftover bytes remain, indicating a malformed or concatenated stream.
Solutions
- Inspect the file for data after the IEND chunk and strip the trailing bytes.
- Verify chunk lengths with pngcheck to find where parsing desynchronized.
- Re-export/re-save the image with a standard tool to normalize the file.
- Treat it as user-facing corruption: re-download the asset rather than trimming blindly.
Example fix
// before: file has trailing garbage after IEND PngReadHelper.read(is, reader); // Completed IEND but 1024 byte(s) remain // after: trim to end of IEND chunk byte[] png = trimAfterIEND(Files.readAllBytes(file)); PngReadHelper.read(new ByteArrayInputStream(png), reader);
Defensive patterns
Strategy: try-catch
Validate before calling
// ensure nothing follows IEND
static long bytesAfterIEND(Path f) throws IOException {
byte[] d = Files.readAllBytes(f);
long off = 8;
while (off + 8 <= d.length) {
int len = ((d[(int)off]&0xff)<<24)|((d[(int)off+1]&0xff)<<16)|((d[(int)off+2]&0xff)<<8)|(d[(int)off+3]&0xff);
String type = new String(d, (int) off + 4, 4, StandardCharsets.US_ASCII);
off += 12 + len;
if (type.equals("IEND")) return d.length - off;
}
return -1; // no IEND: different error
} Try / catch
try {
PngReadHelper.read(is, reader);
} catch (PngException e) {
if (e.getCode() == PngConstants.ERROR_EOF_EXPECTED) {
LOG.warning("trailing data after IEND; sanitizing file");
is = new ByteArrayInputStream(trimAfterIEND(raw));
return PngReadHelper.read(is, reader);
}
throw e;
} Prevention
- Sanitize third-party images (strip post-IEND data) before decoding.
- Avoid concatenating PNG files; use archives instead.
- Run pngcheck to catch bad chunk lengths that desync parsing.
- Re-save suspicious files with a standard image tool.
When it happens
Trigger: Reading a stream with data appended after IEND — e.g. two PNGs concatenated, a PNG with an appended archive/signature block, or a stream where a chunk length mis-parse caused IEND to be detected early.
Common situations: Files padded or signed by tools (some distributors append data); naive concatenation of images; corrupted chunk length fields causing desynchronization so IEND is read at the wrong offset.
Related errors
- ERROR_NOT_PNG
- fcTL chunk length must be
- acTL chunk length must be
- ARGB8888 doesn't support PNG mode
- bKGD chunk received before IHDR chunk
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/dc7acbd6f5fc4bc6.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/reader/PngReadHelper.java:71
*/
public static <ResultT> ResultT read(InputStream is, PngReader<ResultT> reader) throws PngException {
try {
if (!PngReadHelper.readSignature(is)) {
throw new PngException(PngConstants.ERROR_NOT_PNG, "Failed to read PNG signature");
}
// PngAtOnceSource source = PngAtOnceSource.from(is);//, sourceName);
PngSource source = new PngStreamSource(is);
boolean finished = false;
while (!finished) {
int length = source.readInt();
int code = source.readInt();
finished = reader.readChunk(source, code, length);
}
if (source.available() > 0) { // Should trailing data after IEND always be error or can configure as warning?
throw new PngException(PngConstants.ERROR_EOF_EXPECTED, String.format("Completed IEND but %d byte(s) remain", source.available()));
}
reader.finishedChunks(source);
return reader.getResult();
} catch (EOFException e) {
throw new PngException(PngConstants.ERROR_EOF, "Unexpected EOF", e);
} catch (IOException e) {
throw new PngException(PngConstants.ERROR_UNKNOWN_IO_FAILURE, e.getMessage(), e);
}
}
/**
* Number of bytes per row is key to processing scanlines.
* <p>
* TODO: should this by on the header?View on GitHub (pinned to 24702dc5a0)