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

  1. Call player.unload() before the second player.load().
  2. To switch sources, create a fresh player: unload + detachMediaElement on the old instance, then createPlayer/attach/load again.
  3. 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

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


AI-assisted analysis of bilibili/flv.js@42343088f2 (2026-09-01). Data as JSON: /api/errors/4752c8fbfd4ba30c. Report an issue: GitHub.