videojs/video.js · error · Error

Invalid target for ${objName(obj)}#${fnName}; must be a DOM

Error message

Invalid target for ${objName(obj)}#${fnName}; must be a DOM node or evented object.

What it means

The evented mixin (on/one/off/trigger) only operates on targets that are DOM nodes (have a nodeName) or objects already mixed-in with evented (isEvented). This prevents silently attaching listeners to plain objects that have no event bus element. The error names the calling object and method (objName#fnName) for quick localization.

Source

Thrown at src/js/mixins/evented.js:99

/**
 * Validates a value to determine if it is a valid event target. Throws if not.
 *
 * @private
 * @throws {Error}
 *         If the target does not appear to be a valid event target.
 *
 * @param  {Object} target
 *         The object to test.
 *
 * @param  {Object} obj
 *         The evented object we are validating for
 *
 * @param  {string} fnName
 *         The name of the evented mixin function that called this.
 */
const validateTarget = (target, obj, fnName) => {
  if (!target || (!target.nodeName && !isEvented(target))) {
    throw new Error(`Invalid target for ${objName(obj)}#${fnName}; must be a DOM node or evented object.`);
  }
};

/**
 * Validates a value to determine if it is a valid event target. Throws if not.
 *
 * @private
 * @throws {Error}
 *         If the type does not appear to be a valid event type.
 *
 * @param  {string|Array} type
 *         The type to test.
 *
 * @param  {Object} obj
*         The evented object we are validating for
 *
 * @param  {string} fnName
 *         The name of the evented mixin function that called this.

View on GitHub (pinned to c3a7e0e6d2)

Solutions

  1. Pass the DOM element directly: component.on(el, 'click', fn).
  2. Make the target evented first: videojs.obj.evented(target) (or apply evented() in your class) before using it as a target.
  3. If you only need self-events, call on('type', fn) with no target — the component's own eventBusEl_ is used.

Example fix

// before
player.on({handleEvent(){}}, 'play', fn); // plain object
// after
const target = document.querySelector('#btn');
player.on(target, 'click', fn);
Defensive patterns

Strategy: type-guard

Validate before calling

function isValidEventTarget(t) {
  return Boolean(t && (t.nodeName || videojs.obj && videojs.obj.isEvented && videojs.obj.isEvented(t)));
}
if (!isValidEventTarget(target)) throw new TypeError('bad event target');

Type guard

const isEventTarget = (t) =>
  Boolean(t) && (typeof t.nodeName === 'string' || videojs.obj.isEvented(t));

Prevention

When it happens

Trigger: Calling component.on(plainObj, 'click', fn), component.off({}, ...), or component.trigger(null) where the target is neither a DOM node nor an evented object.

Common situations: Passing a jQuery wrapper, a plain config object, or a DOM selector string instead of an element; mixing video.js events with another library's objects; refactoring that loses the el reference.

Related errors


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