bilibili/flv.js · error · IllegalStateException

HTMLMediaElement must be attached before load()!

Error message

HTMLMediaElement must be attached before load()!

What it means

NativePlayer.load() drives playback by assigning the media URL to an HTMLMediaElement that was previously passed to attachMediaElement(). If no media element is attached, there is nothing to load into, so load() throws IllegalStateException. The API contract requires attachMediaElement() before any load() call.

Source

Thrown at src/player/native-player.js:117

        }
    }

    detachMediaElement() {
        if (this._mediaElement) {
            this._mediaElement.src = '';
            this._mediaElement.removeAttribute('src');
            this._mediaElement.removeEventListener('loadedmetadata', this.e.onvLoadedMetadata);
            this._mediaElement = null;
        }
        if (this._statisticsReporter != null) {
            window.clearInterval(this._statisticsReporter);
            this._statisticsReporter = null;
        }
    }

    load() {
        if (!this._mediaElement) {
            throw new IllegalStateException('HTMLMediaElement must be attached before load()!');
        }
        this._mediaElement.src = this._mediaDataSource.url;

        if (this._mediaElement.readyState > 0) {
            this._mediaElement.currentTime = 0;
        }

        this._mediaElement.preload = 'auto';
        this._mediaElement.load();
        this._statisticsReporter = window.setInterval(
            this._reportStatisticsInfo.bind(this),
        this._config.statisticsInfoReportInterval);
    }

    unload() {
        if (this._mediaElement) {
            this._mediaElement.src = '';
            this._mediaElement.removeAttribute('src');

View on GitHub (pinned to 42343088f2)

Solutions

  1. Call player.attachMediaElement(document.querySelector('video')) before player.load()
  2. Ensure attach happens before load() in async setup code (attach in a .then() before invoking load)
  3. If the player was destroyed, create a new instance instead of reusing it
  4. Guard the call: only invoke load() when a media element is still attached

Example fix

// before
const player = flvjs.createPlayer({ type: 'flv', url: 'http://example.com/live.flv' });
player.load(); // throws: HTMLMediaElement must be attached before load()!

// after
const player = flvjs.createPlayer({ type: 'flv', url: 'http://example.com/live.flv' });
player.attachMediaElement(document.getElementById('videoElement'));
player.load();
Defensive patterns

Strategy: try-catch

Validate before calling

if (!player._mediaElement /* or track attachment yourself */) {
  player.attachMediaElement(document.getElementById('videoElement'));
}
player.load();

// cleaner: track attachment in your own code
let attached = false;
player.attachMediaElement(videoEl); attached = true;
if (attached) player.load();

Type guard

function isAttached(player) {
  return player != null && typeof player.attachMediaElement === 'function' && !!player._mediaElement;
}

Try / catch

try {
  player.load();
} catch (e) {
  if (e instanceof flvjs.CustomException || /must be attached/.test(e.message)) {
    player.attachMediaElement(videoElement);
    player.load();
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling player.load() without ever calling player.attachMediaElement(videoEl), or after calling detachMediaElement()/destroy() which nulls this._mediaElement.

Common situations: Skipping the attach step in setup code; calling load() after a destroy()/re-init cycle; attaching inside an async callback that hasn't resolved yet while load() is invoked synchronously; reusing a destroyed player instance.

Related errors


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