{"record":{"id":"c8c260882d5af4b8","repo":"google/ExoPlayer","slug":"invalid-utf-8-sequence-first-byte-value","errorCode":null,"errorMessage":"Invalid UTF-8 sequence first byte: {value}","messagePattern":"Invalid UTF-8 sequence first byte: (.+?)","errorType":"exception","errorClass":"NumberFormatException","httpStatus":null,"severity":"error","filePath":"library/common/src/main/java/com/google/android/exoplayer2/util/ParsableByteArray.java","lineNumber":590,"sourceCode":"   * @return Decoded long value\n   */\n  public long readUtf8EncodedLong() {\n    int length = 0;\n    long value = data[position];\n    // find the high most 0 bit\n    for (int j = 7; j >= 0; j--) {\n      if ((value & (1 << j)) == 0) {\n        if (j < 6) {\n          value &= (1 << j) - 1;\n          length = 7 - j;\n        } else if (j == 7) {\n          length = 1;\n        }\n        break;\n      }\n    }\n    if (length == 0) {\n      throw new NumberFormatException(\"Invalid UTF-8 sequence first byte: \" + value);\n    }\n    for (int i = 1; i < length; i++) {\n      int x = data[position + i];\n      if ((x & 0xC0) != 0x80) { // if the high most 0 bit not 7th\n        throw new NumberFormatException(\"Invalid UTF-8 sequence continuation byte: \" + value);\n      }\n      value = (value << 6) | (x & 0x3F);\n    }\n    position += length;\n    return value;\n  }\n\n  /**\n   * Reads a UTF byte order mark (BOM) and returns the UTF {@link Charset} it represents. Returns\n   * {@code null} without advancing {@link #getPosition() position} if no BOM is found.\n   */\n  @Nullable\n  public Charset readUtfCharsetFromBom() {","sourceCodeStart":572,"sourceCodeEnd":608,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/library/common/src/main/java/com/google/android/exoplayer2/util/ParsableByteArray.java#L572-L608","documentation":"Thrown by ParsableByteArray.readUtf8CodePointUntilDelimiter / the UTF-8 code-point reader (used by readStringUntil and friends) when the FIRST byte of a character cannot start a valid UTF-8 sequence — the bit scan (j from 7 down) found no leading-zero bit position that yields length 1-4, i.e. the byte is 0xFF or 0xFE (all/leading ones), which are never legal UTF-8 lead bytes. It surfaces as NumberFormatException because the method decodes a numeric code point.","triggerScenarios":"Reading a string from a buffer whose position lands on binary garbage: 0xFF bytes appear in ID3 padding gone wrong, misaligned subtitle cues, encrypted/scrambled segments being parsed as plaintext, or when getPosition() was advanced incorrectly so a length/metadata binary field is consumed as text.","commonSituations":"HLS/DASH subtitle and metadata parsers hitting partially downloaded or CORS-corrupted responses; custom DataSource returning uncleared buffers; wrong charset assumption (UTF-16 data read as UTF-8); encrypted HLS segments parsed without the decryption key applied first.","solutions":["Verify the data source actually delivered decrypted, complete bytes (check Content-Length, response code, and that a DataSourceError/HttpDataSource exception wasn't swallowed)","Bounds/alignment check: hex-dump bytes around position before readStringUntil and confirm the expected delimiter exists","Use readStringUntil with a correct delimiter, or read a length-prefixed string, rather than free-running scans into binary regions","Catch the NumberFormatException per item and skip/drop the malformed cue/section so playback continues"],"exampleFix":"// before\nString title = data.readStringUntil((byte) '\\n'); // hits 0xFF in corrupted ID3 padding\n// after\ntry {\n  String title = data.readStringUntil((byte) '\\n');\n} catch (NumberFormatException e) {\n  Log.w(TAG, \"Malformed metadata, skipping\", e);\n  title = \"\";\n}","handlingStrategy":"try-catch","validationCode":"int first = p.peekUnsignedByte();\nif ((first & 0xFE) == 0xFE) { // 0xFF/0xFE can never start UTF-8\n  // skip this region instead of reading a string\n}","typeGuard":null,"tryCatchPattern":"try { s = p.readStringUntil(delim); } catch (NumberFormatException e) { /* log and skip the malformed entry, continue parsing */ }","preventionTips":["Validate responses (status, length, decryption) before parsing as text","Prefer length-prefixed string reads over delimiter scans in binary regions","Keep subtitle/metadata parsing fault-isolated per item"],"tags":["parsing","utf-8","string","corruption"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}