nilaoda/N_m3u8DL-RE · error · Exception

Bad vtt!

Error message

Bad vtt!

What it means

WebVttSub.Parse throws this when the input text does not begin with the mandatory 'WEBVTT' header. The WebVTT specification requires every valid subtitle file to start with 'WEBVTT' on its first line, so the parser rejects anything else up front instead of failing later with confusing cue-parsing errors.

Solutions

  1. Verify the source actually serves WebVTT: check that the content begins with 'WEBVTT' before calling Parse.
  2. If the content is SRT, convert it to WebVTT first (add the WEBVTT header and replace comma decimal separators in timestamps with dots).
  3. Strip any UTF-8 BOM or leading whitespace/BOM bytes before parsing.
  4. Wrap Parse in try/catch and surface a clear 'not a WebVTT file' message to the user.

Example fix

// before
var sub = WebVttSub.Parse(downloadedText);

// after
downloadedText = downloadedText.TrimStart('\ufeff');
if (!downloadedText.TrimStart().StartsWith("WEBVTT"))
    throw new Exception("Downloaded subtitle is not WebVTT (missing WEBVTT header)");
var sub = WebVttSub.Parse(downloadedText);
Defensive patterns

Strategy: validation

Validate before calling

if (string.IsNullOrWhiteSpace(text) || !text.TrimStart('\ufeff').TrimStart().StartsWith("WEBVTT"))
    throw new ArgumentException("Input is not a WebVTT file (missing WEBVTT header)");

Type guard

static bool IsWebVtt(string text) => !string.IsNullOrWhiteSpace(text) && text.TrimStart('\ufeff').TrimStart().StartsWith("WEBVTT");

Try / catch

try { var sub = WebVttSub.Parse(text); }
catch (Exception ex) when (ex.Message == "Bad vtt!") { /* handle non-WebVTT input */ }

Prevention

When it happens

Trigger: Calling WebVttSub.Parse(string) with a string whose Trim() does not start with "WEBVTT" — e.g. an SRT file, an HTML error page, empty content, or a byte-order-mark/mojibake-corrupted header.

Common situations: Downloading subtitle segments that are actually SRT or VTT sprites, a proxy/CDN returning an HTML error page instead of the .vtt file, saving the file with a UTF-8 BOM handled as text before 'WEBVTT', or passing an empty/default string.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of nilaoda/N_m3u8DL-RE@e113dee70c (2026-09-13). Data as JSON: /api/errors/0497b08e1251b127. Report an issue: GitHub.

Appendix: source

Thrown at src/N_m3u8DL-RE.Common/Entity/WebVttSub.cs:49

    /// 从字节数组解析WEBVTT
    /// </summary>
    /// <param name="textBytes"></param>
    /// <param name="encoding"></param>
    /// <returns></returns>
    public static WebVttSub Parse(byte[] textBytes, Encoding encoding, long BaseTimestamp = 0L)
    {
        return Parse(encoding.GetString(textBytes), BaseTimestamp);
    }

    /// <summary>
    /// 从字符串解析WEBVTT
    /// </summary>
    /// <param name="text"></param>
    /// <returns></returns>
    public static WebVttSub Parse(string text, long BaseTimestamp = 0L)
    {
        if (!text.Trim().StartsWith("WEBVTT"))
            throw new Exception("Bad vtt!");

        text += Environment.NewLine;

        var webSub = new WebVttSub();
        var needPayload = false;
        var timeLine = "";
        var regex1 = TSMapRegex();

        if (regex1.IsMatch(text))
        {
            var timestamp = TSValueRegex().Match(regex1.Match(text).Value).Groups[1].Value;
            webSub.MpegtsTimestamp = Convert.ToInt64(timestamp);
        }

        var payloads = new List<string>();
        foreach (var line in text.Split('\n'))
        {
            if (line.Contains(" --> "))

View on GitHub (pinned to e113dee70c)