{"record":{"id":"ca919bc4caf82251","repo":"google/ExoPlayer","slug":"unsupported-charset-s","errorCode":null,"errorMessage":"Unsupported charset: %s","messagePattern":"Unsupported charset: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"library/common/src/main/java/com/google/android/exoplayer2/util/ParsableByteArray.java","lineNumber":639,"sourceCode":"        return Charsets.UTF_16LE;\n      }\n    }\n    return null;\n  }\n\n  /**\n   * Returns the index of the next occurrence of '\\n' or '\\r', or {@link #limit} if none is found.\n   */\n  private int findNextLineTerminator(Charset charset) {\n    int stride;\n    if (charset.equals(Charsets.UTF_8) || charset.equals(Charsets.US_ASCII)) {\n      stride = 1;\n    } else if (charset.equals(Charsets.UTF_16)\n        || charset.equals(Charsets.UTF_16LE)\n        || charset.equals(Charsets.UTF_16BE)) {\n      stride = 2;\n    } else {\n      throw new IllegalArgumentException(\"Unsupported charset: \" + charset);\n    }\n    for (int i = position; i < limit - (stride - 1); i += stride) {\n      if ((charset.equals(Charsets.UTF_8) || charset.equals(Charsets.US_ASCII))\n          && Util.isLinebreak(data[i])) {\n        return i;\n      } else if ((charset.equals(Charsets.UTF_16) || charset.equals(Charsets.UTF_16BE))\n          && data[i] == 0x00\n          && Util.isLinebreak(data[i + 1])) {\n        return i;\n      } else if (charset.equals(Charsets.UTF_16LE)\n          && data[i + 1] == 0x00\n          && Util.isLinebreak(data[i])) {\n        return i;\n      }\n    }\n    return limit;\n  }\n","sourceCodeStart":621,"sourceCodeEnd":657,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/library/common/src/main/java/com/google/android/exoplayer2/util/ParsableByteArray.java#L621-L657","documentation":"findNextLineTerminator (backing readSingleLineWithDelimiter and readSingleLine* methods) only supports UTF-8, US-ASCII, UTF-16, UTF-16LE, and UTF-16BE, because line-terminator scanning needs the charset's code-unit stride (1 or 2 bytes). Passing any other java.nio.charset.Charset — UTF-16 with BOM variants handled upstream, but e.g. UTF-32, ISO-8859-1, or a custom charset — throws IllegalArgumentException immediately.","triggerScenarios":"Calling ParsableByteArray.readSingleLine(int length, Charset) or readSingleLineWithDelimiter with Charsets.ISO_8859_1, Charset.forName(\"UTF-32\"), or any non-standard Charset instance. The API accepts any Charset at the type level but only enumerates the five supported constants at runtime.","commonSituations":"Reading HTTP/ICY/HLS headers that declare charset=iso-8859-1 or windows-1252 in Content-Type and forwarding that Charset into the parser; feeding multi-byte UTF-32 streams; custom Datasources reusing ParsableByteArray for exotic encodings.","solutions":["Map unsupported charsets to a supported equivalent before reading: ISO-8859-1/windows-1252 -> US_ASCII or UTF-8 if bytes allow; UTF-32 -> decode the whole buffer manually with new String(bytes, charset)","Read the line as bytes in a supported charset (UTF-8/US_ASCII) and re-decode the resulting String if you need a different character set afterwards","Pre-validate: keep a Set of Charsets.UTF_8/US_ASCII/UTF_16/UTF_16LE/UTF_16BE and check charset membership before calling readSingleLine*","For genuinely non-UTF encodings, bypass these line helpers and implement your own delimiter scan at byte level"],"exampleFix":"// before\nCharset cs = Charset.forName(headerCharset); // e.g. iso-8859-1\nString line = p.readSingleLine(lineLength, cs); // throws\n// after\nCharset cs = normalize(headerCharset); // maps latin-1/cp1252 -> US_ASCII when safe, else UTF-8\nString line = p.readSingleLine(lineLength, cs);","handlingStrategy":"type-guard","validationCode":"private static final Set<Charset> LINE_CHARSETS = Set.of(\n    Charsets.UTF_8, Charsets.US_ASCII,\n    Charsets.UTF_16, Charsets.UTF_16LE, Charsets.UTF_16BE);\nif (!LINE_CHARSETS.contains(charset)) charset = Charsets.UTF_8;","typeGuard":"static boolean isLineReadableCharset(Charset cs) {\n  return cs.equals(Charsets.UTF_8) || cs.equals(Charsets.US_ASCII)\n      || cs.equals(Charsets.UTF_16) || cs.equals(Charsets.UTF_16LE)\n      || cs.equals(Charsets.UTF_16BE);\n}","tryCatchPattern":"Not applicable — validate the Charset before calling readSingleLine*; an IllegalArgumentException here is a programming error.","preventionTips":["Whitelist charsets at the boundary where headers are parsed","Map ISO-8859-1/windows-1252 labels to US_ASCII/UTF-8 handling for readSingleLine, then re-decode the String if needed","Keep a lint/test rule that only the five supported Charsets reach ParsableByteArray line APIs"],"tags":["parsing","charset","encoding","validation"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}