You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
HLSProvider appends its <source> before hls.js attaches, so browsers with native HLS start a second, native load #1871
Chrome 155 on macOS. document.createElement('video').canPlayType('application/x-mpegurl') returns "maybe", so this Chrome plays HLS natively.
What happens
MediaProvider calls provider.setup(), then sets $providerSetup to true at once. HLSProvider.setup() only starts the hls.js import.
Because $providerSetup is true, loadSource() runs next. It calls this.appendSource(src, 'application/x-mpegurl'). The <video> has no src yet, because hls.js has not attached.
Inserting a <source> into an empty media element starts the HTML resource selection algorithm. Chrome can play application/x-mpegurl, so it starts its own native load of the playlist.
When the import finishes, the lib-loader callback runs controller.setup(ctor). That calls attachMedia, which sets a blob src, and then calls loadSource() again. The native load stops, and hls.js plays.
Effect
Every mount sends a second request for the master playlist, from the media element (Playwright resourceType() is media, hls.js requests are xhr).
If the import is slow, the native pipeline also loads the variant playlist and the AES-128 key. That key request does not carry the headers that xhrSetup adds, so an authenticated key endpoint rejects it. If the key host is not in media-src, the page also gets a CSP violation.
In our end-to-end tests, the race also made play() fail to reach playing in about two out of three runs. With the change below, every run played.
Reproduction
Render <MediaPlayer src={{ src: 'https://example.com/stream/master.m3u8', type: 'application/x-mpegurl' }}><MediaProvider /></MediaPlayer> and set provider.library = () => import('hls.js') in onProviderChange.
Open the page in Chrome 155 or later with the DevTools Network panel open.
Two requests for master.m3u8 show: one with initiator type media and one xhr.
Suggested fix
Append the source element only after hls.js has attached. The second loadSource() call from the lib-loader callback then adds it for AirPlay:
With this change, the media element made no playlist or key request in 6 of 6 runs.
Safari on macOS probably has the same race: hls.js 1.7.3 defaults preferManagedMediaSource to false, so it uses MediaSource, and Safari plays HLS natively. Not tested. DASHProvider.loadSource() has the same shape and probably needs the same guard.
Thanks for opening this, and for building with Vidstack.
Vidstack Player is now in security-only maintenance. Until January 2028, we'll merge priority security fixes into 1.x and nothing else, so we're closing issues that aren't security reports.
Migrating with a coding agent? Paste the prompt from the guide's AI Quickstart section into your agent: React · Web components and other frameworks. It installs the Video.js skill, checks the guide's known gaps against your player before changing code, and plans the installation with npx @videojs/cli agents init.
If this still matters to you in Video.js 10, open an issue or discussion in videojs/video.js and link back here so we keep the context.
If this is a security vulnerability, don't add details here. Report it privately as described in SECURITY.md.
Activity
github-actions commentedon Oct 10, 2026
Thanks for opening this, and for building with Vidstack.
Vidstack Player is now in security-only maintenance. Until January 2028, we'll merge priority security fixes into 1.x and nothing else, so we're closing issues that aren't security reports.
The teams behind Vidstack, Plyr, Media Chrome, and Video.js now work on Video.js 10. The migration guide maps Vidstack onto it: React · Web components and other frameworks.
Migrating with a coding agent? Paste the prompt from the guide's AI Quickstart section into your agent: React · Web components and other frameworks. It installs the Video.js skill, checks the guide's known gaps against your player before changing code, and plans the installation with
npx @videojs/cli agents init.If this still matters to you in Video.js 10, open an issue or discussion in videojs/video.js and link back here so we keep the context.
If this is a security vulnerability, don't add details here. Report it privately as described in SECURITY.md.