HLS Debugging

How to fix M3U8 CORS errors

A browser can load only the resources an origin explicitly allows. If your HLS stream works in VLC or a native app but fails in the browser, CORS is often the first thing to check.

CORS stands for Cross-Origin Resource Sharing. It is the browser rule that decides whether JavaScript running on one origin may fetch resources from another origin. HLS playback touches several resource types: the main manifest, variant playlists, media segments, subtitles, and sometimes encryption keys. If any of those endpoints returns the wrong headers, playback can fail even when the URLs are technically alive.

Why the error appears only in the browser

Tools like VLC, ffmpeg, or native mobile players do not enforce the same web security policy as a browser. That is why a stream may look healthy in one environment and still fail on a normal webpage. A browser-based player is useful precisely because it reproduces that client-side restriction.

The headers that matter most

  • Access-Control-Allow-Origin should allow the requesting site or use * when appropriate.
  • Access-Control-Allow-Methods should support the methods the browser uses.
  • Access-Control-Allow-Headers may matter when custom headers are involved.
  • If credentials or cookies are part of the request, wildcard rules may no longer be sufficient.

Where to check first

Start with the manifest URL. If the player cannot fetch the first M3U8 file, the rest of the stream will never initialize. If the manifest loads but playback still fails, inspect the child playlists and segment requests next. It is common for a top-level manifest to be open while the referenced segment paths point to a different origin with stricter rules.

Common real-world patterns

One frequent mistake is generating signed segment URLs from a CDN domain that does not return the same headers as the main API domain. Another is allowing GET on the manifest but forgetting that the browser may still reject downstream requests because the segment origin responds differently.

If one layer of the HLS request chain is blocked, the player will surface the symptom at playback time even though the first URL may appear healthy.

How to test the fix

After adjusting server headers, return to the live player and test the exact stream again. If the manifest now loads and quality options appear, the top-level access issue is likely resolved. If the player still fails later, move down to segment-level debugging or codec compatibility.