{"record":{"id":"a32f44bff6c72fe4","repo":"HMCL-dev/HMCL","slug":"fdat-chunk-expected-sequence-d-but-received-d","errorCode":null,"errorMessage":"fdAT chunk expected sequence %d but received %d","messagePattern":"fdAT chunk expected sequence (.+?) but received (.+?)","errorType":"exception","errorClass":"PngIntegrityException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/reader/DefaultPngChunkReader.java","lineNumber":253,"sourceCode":"        } else {\n            // fall through\n        }\n\n        processor.processFrameControl(frame);\n    }\n\n    //public abstract void setMainImageOp(PngMainImageOp op);\n\n    @Override\n    public void readFrameImageDataChunk(PngSource source, int dataLength) throws IOException, PngException {\n        // Note that once the sequence number is confirmed as being correct that there\n        // is no need to retain it in subsequent data.\n        int position = source.tell();\n        int sequence = source.readInt();\n        dataLength -= 4; // After reading the sequence number the data is just like IDAT.\n\n        if (sequence != apngSequenceExpect) {\n            throw new PngIntegrityException(String.format(\"fdAT chunk expected sequence %d but received %d\", apngSequenceExpect, sequence));\n        }\n        apngSequenceExpect++; // for next time\n\n        //processFrameData(sequence, source, dataLength);\n        //processFrameImageData(source, dataLength);\n        processor.processFrameImageData(source.slice(dataLength), PngChunkCode.fdAT, source.tell(), dataLength);\n\n//        PngFrameControl current = container.getCurrentAnimationFrame();\n//\n//        //imageDecoder\n//        // TODO: send image bytes to digester\n//        current.appendImageData(new PngChunkMap(PngChunkCode.fdAT, dataLength, position, 0));\n//\n//        // TODO: skip everything except the frame sequence number\n\n\n//        source.skip(dataLength);\n    }","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/reader/DefaultPngChunkReader.java#L235-L271","documentation":"fdAT (frame data) chunks, like fcTL, embed a sequence number that must increment exactly in step with the expected counter apngSequenceExpect. readFrameImageDataChunk reads the first 4 bytes as the sequence number and throws PngIntegrityException if it does not match, since frame data would otherwise be attributed to the wrong frame.","triggerScenarios":"Parsing an APNG where an fdAT chunk's sequence number is out of order, missing, duplicated, or where an IDAT-style payload lost its 4-byte sequence prefix — via readChunk → readFrameImageDataChunk.","commonSituations":"Corrupt or truncated animated PNG downloads; files edited by tools unaware of APNG sequencing; mixtures of IDAT and fdAT after bad conversion; re-encoded streams with gaps.","solutions":["Verify the file's checksum and re-download from the original source.","Re-encode the APNG with ffmpeg/apngasm to regenerate correct sequence numbers.","Use pngcheck or an APNG validator to locate the first bad chunk before parsing.","If resuming a partial stream, sync apngSequenceExpect to the last successfully seen sequence + 1."],"exampleFix":"// before: raw stream throws on gap\nPngReadHelper.read(is, apngReader); // fdAT chunk expected sequence 5 but received 6\n// after: pre-validate chunk ordering\nif (apngSequenceNumbersValid(file)) PngReadHelper.read(is, apngReader); else reencode(file);","handlingStrategy":"validation","validationCode":"// verify fdAT sequence continuity alongside fcTL\nint expect = 0;\nfor (Chunk c : chunks(file)) {\n  if (c.type.equals(\"fcTL\") || c.type.equals(\"fdAT\")) {\n    int seq = readIntBE(c.data, 0);\n    if (seq != expect) throw new IllegalArgumentException(\"seq \" + seq + \" != \" + expect + \" at \" + c.type);\n    expect++;\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  PngReadHelper.read(is, apngReader);\n} catch (PngIntegrityException e) {\n  // corrupt sequencing — recover by re-encoding\n  renderStaticFallback(file); // show first frame or placeholder\n}","preventionTips":["Keep fcTL and fdAT counters in lockstep when generating APNGs.","Use established encoders rather than hand-rolled APNG writers.","Validate with pngcheck before decoding user-supplied files.","Surface PngIntegrityException to users as file corruption."],"tags":["png","apng","sequence-number","corrupt-file"],"backgroundTag":"invalid-state-transition","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}