Skip to content
Players & Playback

HLS Stream Not Playing? 12 Common Causes and Fixes

HLS (.m3u8) stream won't play? Fix CORS, mixed content, 403 and 404 errors, codec problems, broken playlists and live-edge stalls.

HLS Stream Not Playing? 12 Common Causes and Fixes
On this page 18 sections

Few things are as frustrating as a black video box with a spinning wheel. HLS is dependable and plays almost everywhere, but a stream has many moving parts: playlists, segments, keys, CDN rules, codecs and the player itself. When one of them is wrong, playback fails, often with an unhelpful error. If your HLS stream is not playing, the cause is almost always one of the twelve below.

This guide lists the twelve most common reasons an HLS stream will not play, how to spot each one, and how to fix it. Keep our free HLS player open while you work through it: paste your .m3u8 URL and its log shows exactly which stage fails.

Before you start: find where it fails

A quick diagnosis saves time. Open your browser’s developer tools (F12), go to the Network tab, and reload the page with the player.

  • If the master playlist request fails or never appears, the problem is at the start: URL, CORS, permissions or mixed content.
  • If the master loads but a media playlist fails, one rendition is broken.
  • If playlists load but segments fail, look at segment URLs, tokens and CDN rules.
  • If everything downloads but nothing plays, suspect codecs, encryption or timestamps.

Also check the Console tab for errors from the player or the browser.

1. CORS headers are missing

Symptoms: plays in VLC or Safari but not in Chrome with hls.js. The console shows “blocked by CORS policy”. hls.js reports manifestLoadError or fragLoadError with no HTTP status.

Why: browsers block JavaScript from reading responses from another domain unless the server allows it. Web players fetch playlists and segments with JavaScript, so they are subject to CORS.

Fix: configure your storage or CDN to send, on playlists, segments and keys:

Access-Control-Allow-Origin: https://your-site.com
Access-Control-Allow-Methods: GET, HEAD, OPTIONS
Access-Control-Allow-Headers: Range
Access-Control-Expose-Headers: Content-Length, Content-Range

Use * for public streams if you prefer. Remember to also handle OPTIONS preflight requests if the player sends custom headers.

2. Mixed content (http stream on an https page)

Symptoms: nothing loads; the console mentions “Mixed Content” or blocked insecure requests.

Fix: serve the stream over HTTPS. Browsers block HTTP media on HTTPS pages. Most CDNs provide HTTPS at no extra cost.

3. 403 Forbidden: expired or missing tokens

Symptoms: the log shows HTTP 403 on the playlist or segments. Often it worked a few minutes ago.

Why: many CDNs and platforms use signed URLs that expire, or require cookies or headers. A copied URL may no longer be valid, or the token may cover the playlist but not the segments.

Fix: generate fresh signed URLs; make sure tokens are passed to segment requests (via query parameters in the playlist, cookies, or player configuration); check the token lifetime is longer than the viewing session, or refresh it periodically; and confirm clocks on your servers are correct.

4. 404 Not Found: wrong paths

Symptoms: 404 on media playlists or segments.

Why: relative paths in playlists are resolved against the playlist’s own URL. If you moved files, renamed folders, or the playlist uses absolute paths to an old location, the player looks in the wrong place. Live streams can also produce 404s if the player asks for segments that have already been deleted from the live window.

Fix: open the playlist in a browser tab and try each referenced URL by hand. Keep paths relative and folder structures consistent. For live, make sure the playlist window (number of segments kept) is long enough, usually at least three target durations.

5. Unsupported codec

Symptoms: playlists and segments download fine, but you get audio with no video, a black screen, or errors like bufferAddCodecError or manifestIncompatibleCodecsError.

Why: the browser cannot decode the video or audio. Common cases: HEVC in Firefox or on PCs without a hardware decoder, AV1 on older devices, AC-3 audio in browsers that lack it, or High 10 profile H.264.

Fix: include an H.264 High or Main profile rendition with AAC-LC audio as a fallback, and list correct CODECS attributes in the master playlist so players skip what they cannot decode. Check a device with our codec support checker.

6. Missing or wrong CODECS attribute

Symptoms: the player picks a rendition it cannot play, or refuses the stream.

Fix: every #EXT-X-STREAM-INF line should include CODECS with accurate strings, such as avc1.640028,mp4a.40.2. Our M3U8 analyzer flags missing attributes.

7. Segments longer than the target duration

Symptoms: stalls, especially on live streams, or players rejecting the playlist.

Why: the HLS specification requires every segment’s duration, rounded to the nearest integer, to be no longer than #EXT-X-TARGETDURATION. Encoders with irregular keyframes often break this.

Fix: use a fixed keyframe interval that divides evenly into your segment length (for example 2-second keyframes with 6-second segments), and disable scene-cut keyframes. See best encoding settings for streaming.

8. Timestamp and discontinuity problems

Symptoms: playback freezes at a specific point, often around ad breaks or where two videos are joined, or audio drifts out of sync.

Why: timestamps jump or reset between segments without an #EXT-X-DISCONTINUITY tag, or audio and video segments are not aligned.

Fix: mark discontinuities in the playlist where timing resets, keep audio and video in sync during encoding, and avoid stitching segments from different encodes without repackaging.

9. Encryption key cannot be fetched

Symptoms: playlists and segments load, but playback fails with keyLoadError, or the video decodes as garbage.

Why: with AES-128 encryption, the player must download the key from the URI in #EXT-X-KEY. The key server may need authentication, may lack CORS headers, or the key or IV may be wrong.

Fix: open the key URL with the same session and check you get 16 bytes back with HTTP 200 and CORS headers. If the stream uses DRM (FairPlay, Widevine), a generic player will not play it without licence server configuration. See AES-128 vs DRM.

10. Live stream stalls at the live edge

Symptoms: live playback starts, then stalls every few seconds, or keeps falling behind.

Why: the player is trying to play too close to the newest segment, or the playlist updates too slowly because of CDN caching.

Fix: configure the player to stay a few segments behind the edge; cache live playlists for no longer than half the target duration; make sure the encoder is running in real time (check CPU and dropped frames); and for low-latency setups, confirm your CDN supports LL-HLS blocking requests. See low-latency streaming explained.

11. Wrong MIME types

Symptoms: some players or devices refuse the stream, especially smart TVs and older Android devices.

Fix: serve playlists as application/vnd.apple.mpegurl (or application/x-mpegURL), TS segments as video/mp2t, and fMP4 segments as video/mp4 or video/iso.segment. Many storage services default to application/octet-stream, which some players reject.

12. The player or browser itself

Symptoms: works in one browser or player, not another.

Why: old versions of hls.js or Video.js have bugs fixed long ago; some embedded webviews do not support Media Source Extensions; iPhones before iOS 17.1 lack MSE, so hls.js cannot run and only native playback works.

Fix: update your player library, and on Apple devices use the native <video src="...m3u8"> path (most players detect this automatically). Test on the devices your audience actually uses.

A quick checklist

  1. Does the master playlist URL return HTTP 200 in a new tab?
  2. Does it start with #EXTM3U?
  3. Do the media playlists and segments it references load?
  4. Are CORS headers present on all of them?
  5. Is everything served over HTTPS?
  6. Are CODECS strings accurate, and does the device support them?
  7. Do segment durations respect the target duration?
  8. If encrypted, does the key load, or is it DRM?
  9. For live, is the playlist refreshing and is the encoder keeping up?
  10. Is the player library up to date?

Paste the stream into the HLS player and the playlist into the M3U8 analyzer. Between them, they catch most of these problems in under a minute.

When it is not your problem

If you are a viewer rather than the stream owner, some failures are intentional: expired links, geo-restrictions, login requirements and DRM are all designed to stop playback outside the official app or site. The fix in those cases is to watch through the service itself. For background on the format, read what is an M3U8 file.

Useful command-line checks

If you are comfortable with a terminal, these quick checks isolate problems fast:

  • Fetch headers: curl -I https://example.com/master.m3u8 shows the HTTP status, content type and caching headers.
  • Test CORS: curl -I -H "Origin: https://your-site.com" https://example.com/master.m3u8 should return an Access-Control-Allow-Origin header.
  • Inspect a segment: ffprobe -hide_banner segment0.ts reveals codecs, resolution and timestamps.
  • Play outside the browser: ffplay https://example.com/master.m3u8 confirms whether the stream itself is valid, independent of browser rules.

If FFmpeg plays the stream but the browser does not, the problem is almost always CORS, mixed content or codec support in the browser.

Still stuck?

Try a known-good public test stream in the same player. If that plays, the problem is your stream. If it fails too, the problem is the player, the browser or the network you are on.

Summary

Most HLS playback failures come from a short list: CORS, mixed content, expired tokens, wrong paths, unsupported codecs, malformed playlists, key problems and live-edge tuning. Check the network tab to find which request fails, then work through the relevant fix. With accurate CODECS attributes, HTTPS, CORS headers and consistent keyframes, the large majority of HLS streams play everywhere.

Frequently asked questions

Why does my HLS stream play in VLC but not in the browser?

VLC is not subject to browser security rules. The most common reasons are missing CORS headers on the stream server and loading an http:// stream on an https:// page.

Why does my HLS stream work on iPhone but not in Chrome?

Safari plays HLS natively. Chrome needs a JavaScript player such as hls.js, which enforces CORS and supports a narrower set of codecs and containers. Check the codec strings and CORS headers.

What does 'manifestLoadError' mean?

The player could not download the master playlist. Check the URL, the HTTP status (403, 404) and CORS headers.

Keep reading