{"record":{"id":"e4dab7ed0008767b","repo":"HMCL-dev/HMCL","slug":"error-eof","errorCode":"ERROR_EOF","errorMessage":"Unexpected EOF","messagePattern":"Unexpected EOF","errorType":"error_code","errorClass":"PngException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/reader/PngReadHelper.java","lineNumber":79,"sourceCode":"            PngSource source = new PngStreamSource(is);\n            boolean finished = false;\n\n            while (!finished) {\n                int length = source.readInt();\n                int code = source.readInt();\n                finished = reader.readChunk(source, code, length);\n            }\n\n            if (source.available() > 0) { // Should trailing data after IEND always be error or can configure as warning?\n                throw new PngException(PngConstants.ERROR_EOF_EXPECTED, String.format(\"Completed IEND but %d byte(s) remain\", source.available()));\n            }\n\n            reader.finishedChunks(source);\n\n            return reader.getResult();\n\n        } catch (EOFException e) {\n            throw new PngException(PngConstants.ERROR_EOF, \"Unexpected EOF\", e);\n        } catch (IOException e) {\n            throw new PngException(PngConstants.ERROR_UNKNOWN_IO_FAILURE, e.getMessage(), e);\n        }\n\n    }\n\n    /**\n     * Number of bytes per row is key to processing scanlines.\n     * <p>\n     * TODO: should this by on the header?\n     */\n    public static int calculateBytesPerRow(int pixelsPerRow, byte bitDepth, PngColourType colourType, byte interlaceMethod) {\n        if (interlaceMethod != 0) {\n            throw new IllegalStateException(\"Interlaced images not yet supported\");\n\n        } else {\n            int numComponentsPerPixel = colourType.componentsPerPixel; // or \"channels\". e.g. \"gray and alpha\" means two components.\n            int bitsPerComponent = bitDepth; // e.g. \"4\" means 4 bits for gray, 4 bits for alpha","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/reader/PngReadHelper.java#L61-L97","documentation":"The stream ended before the PNG structure was complete (before IEND). PngReadHelper.read catches EOFException and rethrows it as PngException with code ERROR_EOF and message 'Unexpected EOF', so callers get one uniform error type instead of a raw EOFException.","triggerScenarios":"Truncated InputStream: network disconnect mid-download, partially written file, reading only a prefix of the file, or a chunk length field pointing beyond the actual data so reads run off the end.","commonSituations":"Interrupted downloads; reading a file still being written; serving images with a wrong Content-Length causing early cutoff; decoding a fragment of a file.","solutions":["Check the file/stream size and re-download or re-read it completely.","Confirm the file ends with an IEND chunk; if not, the transfer was truncated.","Verify the HTTP transfer completed (Content-Length matched) before decoding.","Catch PngException with code ERROR_EOF and prompt the user to re-fetch the image."],"exampleFix":"// before: decode possibly incomplete stream\nPngReadHelper.read(is, reader); // Unexpected EOF\n// after: ensure fully downloaded first\nbyte[] all = is.readAllBytes();\nif (endsWithIEND(all)) PngReadHelper.read(new ByteArrayInputStream(all), reader);","handlingStrategy":"try-catch","validationCode":"// confirm stream is complete before decoding\nbyte[] all = is.readAllBytes();\nboolean complete = all.length >= 12 && java.util.Arrays.equals(\n    java.util.Arrays.copyOfRange(all, all.length - 12, all.length - 4),\n    \"IEND\".getBytes(StandardCharsets.US_ASCII)) == false\n    ? endsWithIendChunk(all) : endsWithIendChunk(all);","typeGuard":null,"tryCatchPattern":"try {\n  PngReadHelper.read(is, reader);\n} catch (PngException e) {\n  if (e.getCode() == PngConstants.ERROR_EOF) {\n    throw new IOException(\"Image download incomplete, please retry\", e);\n  }\n  throw e;\n}","preventionTips":["Fully download files before decoding; check Content-Length vs actual bytes.","Never decode a file while it is still being written.","Use resumable/verified downloads for large images.","Distinguish ERROR_EOF (truncation) from ERROR_UNKNOWN_IO_FAILURE (read failure) when logging."],"tags":["png","eof","truncated-input"],"backgroundTag":"unexpected-eof","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}