TheAlgorithms/Java · error · IllegalArgumentException

Bad compressed k: {}

Error message

Bad compressed k: {}

What it means

LZW.decompress walks the code list rebuilding the dictionary. For each code k it must either exist in the current dictionary or equal dictSize (the special next-code case). If k is neither in the dictionary nor the next available code, the stream is invalid — the code references a string that cannot be reconstructed, so the method rejects the corrupt input.

Source

Thrown at src/main/java/com/thealgorithms/compression/LZW.java:124

        Map<Integer, String> dictionary = new HashMap<>();
        for (int i = 0; i < dictSize; i++) {
            dictionary.put(i, "" + (char) i);
        }

        // Decompress the first code
        String w = "" + (char) (int) compressed.removeFirst();
        StringBuilder result = new StringBuilder(w);

        for (int k : compressed) {
            String entry;
            if (dictionary.containsKey(k)) {
                // The code is in the dictionary
                entry = dictionary.get(k);
            } else if (k == dictSize) {
                // Special case for sequences like "ababab"
                entry = w + w.charAt(0);
            } else {
                throw new IllegalArgumentException("Bad compressed k: " + k);
            }

            result.append(entry);

            // Add new sequence to the dictionary
            dictionary.put(dictSize++, w + entry.charAt(0));

            w = entry;
        }
        return result.toString();
    }
}

View on GitHub (pinned to fdfb9a395b)

Solutions

  1. Pass the exact List<Integer> returned by LZW.compress without modification.
  2. Verify the list is non-null, ordered, and contains no gaps relative to the expected dictionary growth.
  3. Ensure compress and decompress use the same LZW implementation and initial dictionary (ASCII 0-255 here).

Example fix

// before
List<Integer> codes = readCodesFromFile(); // may be corrupted/partial
String out = LZW.decompress(codes);

// after
List<Integer> codes = LZW.compress(original); // produce + transport intact
String out = LZW.decompress(codes);
Defensive patterns

Strategy: try-catch

Validate before calling

// Cannot fully validate a compressed stream without decoding; best pre-check is structural integrity.
if (compressed == null || compressed.isEmpty()) return "";
// Ensure codes are non-negative and ordered consistently with dictionary growth.
for (int k : compressed) {
    if (k < 0) throw new IllegalArgumentException("Negative code in compressed stream: " + k);
}

Try / catch

try {
    String out = LZW.decompress(compressed);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Bad compressed k:")) {
        // handle corrupt stream: log, request retransmission, or fall back
        throw new IllegalStateException("LZW stream is corrupt or truncated", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling decompress on a hand-edited or truncated list; decompress([99999]) where 99999 is far beyond any dictionary entry; codes reordered or a negative value inserted; mixing codes from a different compression run.

Common situations: The compressed code list was corrupted in storage/transit; a partial list was passed (missing leading codes so the dictionary never grew far enough); codes were produced by a different LZW variant/implementation.

Related errors


AI-assisted analysis of TheAlgorithms/Java@fdfb9a395b (2026-08-13). Data as JSON: /api/errors/463ce38147b45fd4. Report an issue: GitHub.