Test files › Subtitles and captions › missing-signature.vtt

Sample WebVTT file (missing signature)

A WebVTT file with correct cues but no "WEBVTT" first line, which makes the whole file invalid.

↓ Download missing-signature.vtt
Filenamemissing-signature.vtt
FormatWebVTT
Size138 bytes (138 bytes)
MIME typetext/vtt; charset=utf-8
SHA-25650cf66ef41bf05706e150236a4c48c25a65fc23b54c06cfba0c9143abe57b3f2
What this file catchesPlayers that parse cues without checking the signature. The spec requires the file to start with WEBVTT, so a conforming player rejects this outright while a lenient one silently plays it. Tells you which of the two you have built.

Handle it in code

Each snippet below was run against this exact file with Python 3.14.4 and Node 24.15.0 when this page was built, and the output shown is what it printed.

Python

SRT puts a comma before the milliseconds and WebVTT a full stop, and WebVTT files must start with WEBVTT. Players differ on the rest: overlapping cues are legal in WebVTT, but many SRT players show only one of them.

import re

TIME = r"(?:(\d+):)?(\d{2}):(\d{2})([.,])(\d{3})"
CUE = re.compile(TIME + r"\s+-->\s+" + TIME)

def ms(h, m, s, sep, frac):
    return ((int(h or 0) * 60 + int(m)) * 60 + int(s)) * 1000 + int(frac)

name = "missing-signature.vtt"
vtt = name.lower().endswith(".vtt")
with open(name, encoding="utf-8-sig") as f:
    text = f.read()
problems, cues = [], []
if vtt and not text.startswith("WEBVTT"):
    problems.append("line 1: no WEBVTT signature")
for n, line in enumerate(text.splitlines(), 1):
    m = CUE.search(line)
    if not m:
        continue
    g = m.groups()
    right = "." if vtt else ","
    if g[3] != right or g[8] != right:
        problems.append(f"line {n}: {'WebVTT' if vtt else 'SRT'} needs {right!r} before the milliseconds")
    start, end = ms(*g[:5]), ms(*g[5:])
    if end < start:
        problems.append(f"line {n}: the cue ends before it starts")
    elif end == start:
        problems.append(f"line {n}: zero length, so it never shows")
    if cues:
        prev_start, prev_end = cues[-1]
        if start < prev_start:
            problems.append(f"line {n}: starts before the previous cue (out of order)")
        overlap = min(end, prev_end) - max(start, prev_start)
        if overlap > 0:
            problems.append(f"line {n}: overlaps the previous cue by {overlap} ms")
    cues.append((start, end))
print(f"{len(cues)} cues:", "valid" if not problems else f"{len(problems)} problem{'s' * (len(problems) != 1)}")
for p in problems:
    print("  " + p)

Run against this file, it prints: 2 cues: 1 problem line 1: no WEBVTT signature

Related guides and tools

Character encodingsVerify its SHA-256

Download & verify

curl -fsSL -o "missing-signature.vtt" "https://files.hexaqa.com/subtitle/missing-signature.vtt"
curl -fsSL "https://files.hexaqa.com/subtitle/missing-signature.vtt" | sha256sum # expect: 50cf66ef41bf05706e150236a4c48c25a65fc23b54c06cfba0c9143abe57b3f2

More subtitles and captions test files

comma-separator.vttoverlapping-cues.srtvalid.srtvalid.vtt

← All Subtitles and captions files