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
- Ensure the target element exists in the DOM before calling videojs() (defer the script, or wrap in DOMContentLoaded).
- Pass the actual Element reference instead of an id string: videojs(document.getElementById('vid')).
- For framework-driven mounts, call videojs() inside the component's onMounted/afterRender hook.
- 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
- Resolve the element yourself and pass the Element reference, not an id string.
- Run initialization inside DOMContentLoaded or a framework mount hook, not in the document head.
- Confirm the element lives in the same document (no cross-iframe/shadow-root lookups).
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
- currentDimension only accepts width or height value
- Invalid target for ${objName(obj)}#${fnName}; must be a DOM
- class has illegal whitespace characters
- Illegal component name, "${name}"; must be a non-empty strin
- Illegal component, "${name}"; ${reason}.
AI-assisted analysis of videojs/video.js@c3a7e0e6d2 (2026-08-13).
Data as JSON: /api/errors/dfff64820745d313.
Report an issue: GitHub.