videojs/video.js · error · TypeError

The element or ID supplied is not valid. (videojs)

Error message

The element or ID supplied is not valid. (videojs)

What it means

Thrown as a TypeError by the videojs(id) factory when the resolved value is not a DOM element. When id is a string, the factory looks up '#'+normalizeId(id) via Dom.$; when id is not a string it is used directly. Dom.isEl then requires nodeType === 1. This surfaces missing elements, wrong types, and DOM-not-ready conditions.

Source

Thrown at src/js/video.js:146

 *         The `videojs()` function returns a {@link Player|Player} instance.
 */
function videojs(id, options, ready) {
  let player = videojs.getPlayer(id);

  if (player) {
    if (options) {
      log.warn(`Player "${id}" is already initialised. Options will not be applied.`);
    }
    if (ready) {
      player.ready(ready);
    }
    return player;
  }

  const el = (typeof id === 'string') ? Dom.$('#' + normalizeId(id)) : id;

  if (!Dom.isEl(el)) {
    throw new TypeError('The element or ID supplied is not valid. (videojs)');
  }

  // document.body.contains(el) will only check if el is contained within that one document.
  // This causes problems for elements in iframes.
  // Instead, use the element's ownerDocument instead of the global document.
  // This will make sure that the element is indeed in the dom of that document.
  // Additionally, check that the document in question has a default view.
  // If the document is no longer attached to the dom, the defaultView of the document will be null.
  // If element is inside Shadow DOM (e.g. is part of a Custom element), ownerDocument.body
  // always returns false. Instead, use the Shadow DOM root.
  const inShadowDom = 'getRootNode' in el ? el.getRootNode() instanceof window.ShadowRoot : false;
  const rootNode = inShadowDom ? el.getRootNode() : el.ownerDocument.body;

  if (!el.ownerDocument.defaultView || !rootNode.contains(el)) {
    log.warn('The element supplied is not included in the DOM');
  }

  options = options || {};

View on GitHub (pinned to c3a7e0e6d2)

Solutions

  1. Ensure the target element exists in the DOM before calling videojs() (defer the script, or wrap in DOMContentLoaded).
  2. Pass the actual Element reference instead of an id string: videojs(document.getElementById('vid')).
  3. For framework-driven mounts, call videojs() inside the component's onMounted/afterRender hook.
  4. Verify the id spelling and that you are querying the right document (iframe/shadow root).

Example fix

// before (script in <head>)
videojs('vid');
// after
document.addEventListener('DOMContentLoaded', () => videojs(document.getElementById('vid')));
Defensive patterns

Strategy: validation

Validate before calling

function safeVideojs(id, options, ready) {
  const el = typeof id === 'string' ? document.getElementById(id.replace(/^#/, '')) : id;
  if (!el || el.nodeType !== 1) {
    throw new TypeError(`videojs: element not found for id ${id}`);
  }
  return videojs(el, options, ready);
}

Type guard

function isDomEl(v) {
  return v !== null && typeof v === 'object' && v.nodeType === 1;
}

Try / catch

try {
  return videojs(id, options, ready);
} catch (err) {
  if (err instanceof TypeError && /element or ID supplied is not valid/.test(err.message)) {
    document.addEventListener('DOMContentLoaded', () => videojs(id, options, ready), { once: true });
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling videojs('missing-id'); calling videojs() with no args (id is undefined, used directly, fails isEl); passing a jQuery wrapper, document fragment, text node, or array; running the script before the element is parsed (script in head without defer); passing an element inside a different iframe/shadow root that document.querySelector cannot reach.

Common situations: Script in the document head running before DOMContentLoaded; typo in the id attribute; SSR builds where document is mocked; element created later by a framework (React/Vue mount) but videojs() called synchronously before render; double-prefixed id ('#vid' passed as the string, though normalizeId strips a leading '#').

Related errors


AI-assisted analysis of videojs/video.js@c3a7e0e6d2 (2026-08-13). Data as JSON: /api/errors/dfff64820745d313. Report an issue: GitHub.