bilibili/flv.js · error · IllegalStateException
FlvPlayer.load() has been called, please call unload() first
Error message
FlvPlayer.load() has been called, please call unload() first!
What it means
FlvPlayer.load() throws IllegalStateException if this._transmuxer already exists, meaning load() was already called and the playback pipeline is still active. The library requires unload() to tear down the transmuxer before a new load can begin, preventing two concurrent transmuxing pipelines on one player.
Source
Thrown at src/player/flv-player.js:192
this._mediaElement.removeEventListener('loadedmetadata', this.e.onvLoadedMetadata);
this._mediaElement.removeEventListener('seeking', this.e.onvSeeking);
this._mediaElement.removeEventListener('canplay', this.e.onvCanPlay);
this._mediaElement.removeEventListener('stalled', this.e.onvStalled);
this._mediaElement.removeEventListener('progress', this.e.onvProgress);
this._mediaElement = null;
}
if (this._msectl) {
this._msectl.destroy();
this._msectl = null;
}
}
load() {
if (!this._mediaElement) {
throw new IllegalStateException('HTMLMediaElement must be attached before load()!');
}
if (this._transmuxer) {
throw new IllegalStateException('FlvPlayer.load() has been called, please call unload() first!');
}
if (this._hasPendingLoad) {
return;
}
if (this._config.deferLoadAfterSourceOpen && this._mseSourceOpened === false) {
this._hasPendingLoad = true;
return;
}
if (this._mediaElement.readyState > 0) {
this._requestSetTime = true;
// IE11 may throw InvalidStateError if readyState === 0
this._mediaElement.currentTime = 0;
}
this._transmuxer = new Transmuxer(this._mediaDataSource, this._config);
View on GitHub (pinned to 42343088f2)
Solutions
- Call player.unload() before the second player.load().
- To switch sources, create a fresh player: unload + detachMediaElement on the old instance, then createPlayer/attach/load again.
- Guard handlers with a flag or check player._transmuxer before calling load().
Example fix
// before
switchButton.onclick = () => player.load();
// after
switchButton.onclick = () => {
player.unload();
player.load();
}; Defensive patterns
Strategy: try-catch
Validate before calling
function reloadPlayer(player) {
if (player._transmuxer) player.unload();
player.load();
} Type guard
function canLoad(player) {
return !player._transmuxer;
} Try / catch
try {
player.load();
} catch (e) {
if (/please call unload\(\) first/.test(e.message)) {
player.unload();
player.load();
} else throw e;
} Prevention
- Pair every load() with unload() on replay/source-switch/retry paths.
- Centralize playback restart in one function that always unloads first.
- Debounce/lock the load trigger to prevent double invocation.
When it happens
Trigger: Calling player.load() twice without player.unload() in between — e.g. re-invoking load on a seek/quality-switch/replay handler while the first session is still running — at src/player/flv-player.js:192.
Common situations: Implementing 'play again' or source-switch buttons that call load() directly, retry logic retriggering load() after an error without unloading, or load() being called both manually and via attachMediaElement flows.
Related errors
- HTMLMediaElement must be attached before load()!
- HTMLMediaElement must be attached before load()!
- MediaSource has been attached to an HTMLMediaElement!
- Url must be a non-empty string!
- FlvPlayer requires an flv MediaDataSource input!
AI-assisted analysis of bilibili/flv.js@42343088f2 (2026-09-01).
Data as JSON: /api/errors/4752c8fbfd4ba30c.
Report an issue: GitHub.