{"record":{"id":"ea34b8a20162d664","repo":"HMCL-dev/HMCL","slug":"error-not-png","errorCode":"ERROR_NOT_PNG","errorMessage":"Failed to read PNG signature","messagePattern":"Failed to read PNG signature","errorType":"error_code","errorClass":"PngException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/reader/PngReadHelper.java","lineNumber":57,"sourceCode":"            }\n        }\n        return true;\n    }\n\n    /**\n     * Reads a given InputStream using the PngReader to process all chunks until the file is\n     * finished, then returning the result from the PngReader.\n     *\n     * @param is        stream to read\n     * @param reader    reads and delegates processing of all chunks\n     * @param <ResultT> result of the processing\n     * @return result of the processing of the InputStream.\n     * @throws PngException\n     */\n    public static <ResultT> ResultT read(InputStream is, PngReader<ResultT> reader) throws PngException {\n        try {\n            if (!PngReadHelper.readSignature(is)) {\n                throw new PngException(PngConstants.ERROR_NOT_PNG, \"Failed to read PNG signature\");\n            }\n\n//            PngAtOnceSource source = PngAtOnceSource.from(is);//, sourceName);\n            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","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/reader/PngReadHelper.java#L39-L75","documentation":"PngReadHelper.read requires the input stream to begin with the 8-byte PNG signature. readSignature returns false when the leading bytes do not match, and read throws PngException with code ERROR_NOT_PNG, meaning the stream is not a PNG at all.","triggerScenarios":"Passing a non-PNG stream (JPEG, WebP, HTML error page, empty file, gzip-compressed PNG not decompressed first) as the InputStream to PngReadHelper.read.","commonSituations":"Wrong file extension/content confusion after a download; server returning an HTML error page with 200; serving .png.gz without decompression; concatenating files; testing with placeholder files.","solutions":["Check the first bytes of the stream/file — they must be 89 50 4E 47 0D 0A 1A 0A.","Unwrap any compression (e.g. GZIPInputStream) before passing the stream.","Verify the URL/download actually returned a PNG (check Content-Type and HTTP status).","Handle PngException with code ERROR_NOT_PNG to give the user a clear 'not a PNG' message."],"exampleFix":"// before: passing raw (possibly gzipped or HTML) stream\nPngReadHelper.read(is, reader); // Failed to read PNG signature\n// after\nif (!is.markSupported()) is = new BufferedInputStream(is);\nis.mark(8);\nbyte[] head = is.readNBytes(2);\nis.reset();\nif ((head[0] & 0xFF) == 0x1F && (head[1] & 0xFF) == 0x8B) is = new GZIPInputStream(is);\nPngReadHelper.read(is, reader);","handlingStrategy":"validation","validationCode":"// check PNG signature before decoding\nstatic boolean isPng(InputStream is) throws IOException {\n  is.mark(8);\n  byte[] sig = is.readNBytes(8);\n  is.reset();\n  return java.util.Arrays.equals(sig,\n      new byte[]{(byte)0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A});\n}","typeGuard":null,"tryCatchPattern":"try {\n  PngReadHelper.read(is, reader);\n} catch (PngException e) {\n  if (e.getCode() == PngConstants.ERROR_NOT_PNG) {\n    showNotAPngMessage();\n  } else throw e;\n}","preventionTips":["Check Content-Type/extension and sniff magic bytes before decoding.","Decompress gzip streams before handing them to the reader.","Verify HTTP status is 200 and the body is not an HTML error page.","Never assume a .png filename means PNG content."],"tags":["png","invalid-signature","binary-parsing"],"backgroundTag":"invalid-argument-format","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"}