{"record":{"id":"1c7ccbd541f6ef5e","repo":"HMCL-dev/HMCL","slug":"received-trns-data-but-no-palette-is-in-place","errorCode":null,"errorMessage":"Received tRNS data but no palette is in place","messagePattern":"Received tRNS data but no palette is in place","errorType":"exception","errorClass":"PngIntegrityException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/argb8888/BasicArgb8888Director.java","lineNumber":24,"sourceCode":"import org.jackhuang.hmcl.ui.image.apng.error.PngException;\nimport org.jackhuang.hmcl.ui.image.apng.error.PngIntegrityException;\n\n/**\n * Common functionality for Argb8888Director implementations.\n */\npublic abstract class BasicArgb8888Director<ResultT> implements Argb8888Director<ResultT> {\n    protected Argb8888ScanlineProcessor scanlineProcessor;\n\n    @Override\n    public void receivePalette(Argb8888Palette palette) {\n        scanlineProcessor.setPalette(palette);\n    }\n\n    @Override\n    public void processTransparentPalette(byte[] bytes, int position, int length) throws PngException {\n        Argb8888Palette palette = scanlineProcessor.getPalette();\n        if (null == palette) {\n            throw new PngIntegrityException(\"Received tRNS data but no palette is in place\");\n        }\n        if (length <= 0 || length > palette.size()) {\n            throw new PngIntegrityException(String.format(\"Received tRNS data length is invalid. Should be >1 && < %d but is %d\", palette.size(), length));\n        }\n        for (int i = 0; i < length; i++) {\n            final int alpha = 0xff & bytes[position + i];\n            palette.argbArray()[i] = alpha << 24 | palette.argbArray()[i] & 0x00FFFFFF;\n        }\n    }\n\n    @Override\n    public void processTransparentGreyscale(byte k1, byte k0) throws PngException {\n        scanlineProcessor.processTransparentGreyscale(k1, k0);\n    }\n\n    @Override\n    public void processTransparentTruecolour(byte r1, byte r0, byte g1, byte g0, byte b1, byte b0) throws PngException {\n        scanlineProcessor.processTransparentTruecolour(r1, r0, g1, g0, b1, b0);","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/argb8888/BasicArgb8888Director.java#L6-L42","documentation":"PngIntegrityException thrown when a tRNS chunk arrives for a palette-indexed image but no PLTE-derived palette has been registered with the scanline processor. Transparency for indexed colour is expressed as alpha per palette entry, so applying tRNS without a palette is meaningless and indicates chunks arrived out of order or the PLTE chunk was missing.","triggerScenarios":"Calling processTransparentPalette on a BasicArgb8888Director when scanlineProcessor.getPalette() returns null — i.e. processPalette was never called (or the PLTE chunk was absent/skipped) before the tRNS chunk was processed.","commonSituations":"PNG streams whose tRNS precedes PLTE or whose PLTE was dropped by a chunk filter; truncated palette images missing PLTE; custom parsers feeding chunks to the director in the wrong order; files malformed by broken muxers.","solutions":["Ensure the PLTE chunk is processed (processPalette called) before tRNS reaches processTransparentPalette — fix chunk ordering in the parser","Reject PNGs whose tRNS appears without a preceding PLTE as structurally invalid","If a chunk filter is in use, stop filtering out PLTE when tRNS is present","Catch PngIntegrityException and treat the stream as malformed or skip transparency handling"],"exampleFix":"// before: tRNS delivered before PLTE\ndirector.processTransparentPalette(trns, 0, trns.length); // throws: no palette\n// after: process palette first\ndirector.processPalette(plte, 0, plte.length);\ndirector.processTransparentPalette(trns, 0, trns.length); // OK","handlingStrategy":"validation","validationCode":"if (chunkSeen(\"tRNS\") && !chunkSeen(\"PLTE\")) {\n    throw new IllegalArgumentException(\"tRNS chunk requires a preceding PLTE chunk\");\n}","typeGuard":"boolean paletteReady(Argb8888Director director) {\n    return director.scanlineProcessor.getPalette() != null;\n}","tryCatchPattern":"try {\n    director.processTransparentPalette(bytes, position, length);\n} catch (PngIntegrityException e) {\n    LOG.warn(\"tRNS without palette (missing/out-of-order PLTE): \" + e.getMessage());\n    // treat stream as malformed or continue without transparency\n}","preventionTips":["Enforce PNG chunk ordering rules in your parser (PLTE must precede tRNS)","Do not filter out PLTE from chunk streams that carry tRNS","Track seen-chunk state and validate dependencies before dispatching","Reject truncated images missing mandatory chunks such as PLTE for indexed colour"],"tags":["png","palette","transparency","chunk-order"],"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"}