bilibili/flv.js · error · IllegalStateException
MediaSource has been attached to an HTMLMediaElement!
Error message
MediaSource has been attached to an HTMLMediaElement!
What it means
attachMediaElement() creates a new MediaSource and wires it to the given HTMLMediaElement. The library throws IllegalStateException if this MSEController instance already has a MediaSource, because a MediaSource can only ever be attached to one media element and one controller instance. It signals a lifecycle/reuse mistake rather than a runtime failure.
Source
Thrown at src/core/mse-controller.js:101
if (this._mediaElement || this._mediaSource) {
this.detachMediaElement();
}
this.e = null;
this._emitter.removeAllListeners();
this._emitter = null;
}
on(event, listener) {
this._emitter.addListener(event, listener);
}
off(event, listener) {
this._emitter.removeListener(event, listener);
}
attachMediaElement(mediaElement) {
if (this._mediaSource) {
throw new IllegalStateException('MediaSource has been attached to an HTMLMediaElement!');
}
let ms = this._mediaSource = new window.MediaSource();
ms.addEventListener('sourceopen', this.e.onSourceOpen);
ms.addEventListener('sourceended', this.e.onSourceEnded);
ms.addEventListener('sourceclose', this.e.onSourceClose);
this._mediaElement = mediaElement;
this._mediaSourceObjectURL = window.URL.createObjectURL(this._mediaSource);
mediaElement.src = this._mediaSourceObjectURL;
}
detachMediaElement() {
if (this._mediaSource) {
let ms = this._mediaSource;
for (let type in this._sourceBuffers) {
// pending segments should be discard
let ps = this._pendingSegments[type];
ps.splice(0, ps.length);View on GitHub (pinned to 42343088f2)
Solutions
- Create a new player (or new MSEController) instead of reusing the instance for a second attach
- Detach the element and destroy the old player before attaching: call player.unload() / player.detachMediaElement() / player.destroy(), then build a fresh player
- In UI frameworks, guard effects so attach runs once (or clean up in the effect's teardown by destroying the player)
Example fix
// before const player = createPlayer(mds); player.attachMediaElement(videoEl); // later, same player: player.attachMediaElement(newVideoEl); // throws // after player.destroy(); const player2 = createPlayer(mds); player2.attachMediaElement(newVideoEl);
Defensive patterns
Strategy: validation
Validate before calling
if (player && typeof player.attachMediaElement === 'function' && !player._mediaElement && !player._mediaSource) {
player.attachMediaElement(videoEl);
} else {
player.destroy();
player = createPlayer(mds, config);
player.attachMediaElement(videoEl);
} Type guard
function canAttach(player) {
return player != null && typeof player.attachMediaElement === 'function' && !player._mediaSource;
} Try / catch
try {
player.attachMediaElement(videoEl);
} catch (e) {
if (e.name === 'IllegalStateException') {
player.destroy();
player = createPlayer(mds, config);
player.attachMediaElement(videoEl);
} else { throw e; }
} Prevention
- Create a fresh player for each attach; never reuse a player across media elements
- In React/Vue effects, attach once and destroy in cleanup to survive StrictMode double-mounts
- Call detachMediaElement()/destroy() before discarding a player
- Keep player instances out of module/global singletons unless you manage their lifecycle explicitly
When it happens
Trigger: Calling player.attachMediaElement(el) a second time on the same player instance (e.g. after re-attaching to a new <video> element, or a React re-render/mount calling attach again), or calling it after destroy() left stale state.
Common situations: React/Vue StrictMode double-mounting components that call attachMediaElement in an effect; hot module reloading; trying to re-point one player to another video element without recreating the player; calling attach on a reused singleton player.
Related errors
- HTMLMediaElement must be attached before load()!
- FlvPlayer.load() has been called, please call unload() first
- HTMLMediaElement must be attached before load()!
AI-assisted analysis of bilibili/flv.js@42343088f2 (2026-09-01).
Data as JSON: /api/errors/b43fbd7b821631af.
Report an issue: GitHub.