HMCL-dev/HMCL · error · PngIntegrityException
Received tRNS data but no palette is in place
Error message
Received tRNS data but no palette is in place
What it means
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.
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
Example fix
// before: tRNS delivered before PLTE director.processTransparentPalette(trns, 0, trns.length); // throws: no palette // after: process palette first director.processPalette(plte, 0, plte.length); director.processTransparentPalette(trns, 0, trns.length); // OK
Defensive patterns
Strategy: validation
Validate before calling
if (chunkSeen("tRNS") && !chunkSeen("PLTE")) {
throw new IllegalArgumentException("tRNS chunk requires a preceding PLTE chunk");
} Type guard
boolean paletteReady(Argb8888Director director) {
return director.scanlineProcessor.getPalette() != null;
} Try / catch
try {
director.processTransparentPalette(bytes, position, length);
} catch (PngIntegrityException e) {
LOG.warn("tRNS without palette (missing/out-of-order PLTE): " + e.getMessage());
// treat stream as malformed or continue without transparency
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- tRNS chunk for greyscale image must be exactly length=2, not
- Illegal to have tRNS chunk with image type
- Invalid indexed colour bit-depth
- Invalid palette data length
- bKGD chunk received before IHDR chunk
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/1c7ccbd541f6ef5e.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/ui/image/apng/argb8888/BasicArgb8888Director.java:24
import org.jackhuang.hmcl.ui.image.apng.error.PngException;
import org.jackhuang.hmcl.ui.image.apng.error.PngIntegrityException;
/**
* Common functionality for Argb8888Director implementations.
*/
public abstract class BasicArgb8888Director<ResultT> implements Argb8888Director<ResultT> {
protected Argb8888ScanlineProcessor scanlineProcessor;
@Override
public void receivePalette(Argb8888Palette palette) {
scanlineProcessor.setPalette(palette);
}
@Override
public void processTransparentPalette(byte[] bytes, int position, int length) throws PngException {
Argb8888Palette palette = scanlineProcessor.getPalette();
if (null == palette) {
throw new PngIntegrityException("Received tRNS data but no palette is in place");
}
if (length <= 0 || length > palette.size()) {
throw new PngIntegrityException(String.format("Received tRNS data length is invalid. Should be >1 && < %d but is %d", palette.size(), length));
}
for (int i = 0; i < length; i++) {
final int alpha = 0xff & bytes[position + i];
palette.argbArray()[i] = alpha << 24 | palette.argbArray()[i] & 0x00FFFFFF;
}
}
@Override
public void processTransparentGreyscale(byte k1, byte k0) throws PngException {
scanlineProcessor.processTransparentGreyscale(k1, k0);
}
@Override
public void processTransparentTruecolour(byte r1, byte r0, byte g1, byte g0, byte b1, byte b0) throws PngException {
scanlineProcessor.processTransparentTruecolour(r1, r0, g1, g0, b1, b0);View on GitHub (pinned to 24702dc5a0)