{"record":{"id":"b43fbd7b821631af","repo":"bilibili/flv.js","slug":"mediasource-has-been-attached-to-an-htmlmediaeleme","errorCode":null,"errorMessage":"MediaSource has been attached to an HTMLMediaElement!","messagePattern":"MediaSource has been attached to an HTMLMediaElement!","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/core/mse-controller.js","lineNumber":101,"sourceCode":"        if (this._mediaElement || this._mediaSource) {\n            this.detachMediaElement();\n        }\n        this.e = null;\n        this._emitter.removeAllListeners();\n        this._emitter = null;\n    }\n\n    on(event, listener) {\n        this._emitter.addListener(event, listener);\n    }\n\n    off(event, listener) {\n        this._emitter.removeListener(event, listener);\n    }\n\n    attachMediaElement(mediaElement) {\n        if (this._mediaSource) {\n            throw new IllegalStateException('MediaSource has been attached to an HTMLMediaElement!');\n        }\n        let ms = this._mediaSource = new window.MediaSource();\n        ms.addEventListener('sourceopen', this.e.onSourceOpen);\n        ms.addEventListener('sourceended', this.e.onSourceEnded);\n        ms.addEventListener('sourceclose', this.e.onSourceClose);\n\n        this._mediaElement = mediaElement;\n        this._mediaSourceObjectURL = window.URL.createObjectURL(this._mediaSource);\n        mediaElement.src = this._mediaSourceObjectURL;\n    }\n\n    detachMediaElement() {\n        if (this._mediaSource) {\n            let ms = this._mediaSource;\n            for (let type in this._sourceBuffers) {\n                // pending segments should be discard\n                let ps = this._pendingSegments[type];\n                ps.splice(0, ps.length);","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/bilibili/flv.js/blob/42343088f22619cf014a057b3878fe3d320016a6/src/core/mse-controller.js#L83-L119","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)"],"exampleFix":"// before\nconst player = createPlayer(mds);\nplayer.attachMediaElement(videoEl);\n// later, same player:\nplayer.attachMediaElement(newVideoEl); // throws\n// after\nplayer.destroy();\nconst player2 = createPlayer(mds);\nplayer2.attachMediaElement(newVideoEl);","handlingStrategy":"validation","validationCode":"if (player && typeof player.attachMediaElement === 'function' && !player._mediaElement && !player._mediaSource) {\n  player.attachMediaElement(videoEl);\n} else {\n  player.destroy();\n  player = createPlayer(mds, config);\n  player.attachMediaElement(videoEl);\n}","typeGuard":"function canAttach(player) {\n  return player != null && typeof player.attachMediaElement === 'function' && !player._mediaSource;\n}","tryCatchPattern":"try {\n  player.attachMediaElement(videoEl);\n} catch (e) {\n  if (e.name === 'IllegalStateException') {\n    player.destroy();\n    player = createPlayer(mds, config);\n    player.attachMediaElement(videoEl);\n  } else { throw e; }\n}","preventionTips":["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"],"tags":["mediasource","lifecycle","mse","reinitialization"],"backgroundTag":"mediasource-already-attached","analyzedSha":"42343088f22619cf014a057b3878fe3d320016a6","analyzedAt":"2026-09-01T00:27:28.147Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}