videojs/video.js · error · Error
Plugin must be sub-classed; not directly instantiated.
Error message
Plugin must be sub-classed; not directly instantiated.
What it means
The Plugin base class is abstract: it sets up evented state, logging, and version tracking that only make sense on a subclass with a name and per-instance disposal. Direct instantiation (new Plugin(player)) would lack these and break plugin lifecycle hooks, so the constructor refuses.
Source
Thrown at src/js/plugin.js:200
* @fires Player#pluginsetup:$name
* @listens Player#dispose
* @throws {Error}
* If attempting to instantiate the base {@link Plugin} class
* directly instead of via a sub-class.
*/
class Plugin {
/**
* Creates an instance of this class.
*
* Sub-classes should call `super` to ensure plugins are properly initialized.
*
* @param {Player} player
* A Video.js player instance.
*/
constructor(player) {
if (this.constructor === Plugin) {
throw new Error('Plugin must be sub-classed; not directly instantiated.');
}
this.player = player;
if (!this.log) {
this.log = this.player.log.createLogger(this.name);
}
// Make this object evented, but remove the added `trigger` method so we
// use the prototype version instead.
evented(this);
delete this.trigger;
stateful(this, this.constructor.defaultState);
markPluginAsActive(player, this.name);
// Auto-bind the dispose method so we can use it as a listener and unbind
// it later easily.View on GitHub (pinned to c3a7e0e6d2)
Solutions
- Define a subclass: class MyPlugin extends videojs.getPlugin('plugin') { ... } and register it, then use player.myPlugin().
- Never instantiate the base Plugin; use registerPlugin(name, factory) for basic plugins instead.
- If you only need a basic plugin, register a plain function via videojs.registerPlugin(name, fn).
Example fix
// before
const Plugin = videojs.getPlugin('plugin');
new Plugin(player); // throws
// after
class MyPlugin extends videojs.getPlugin('plugin') {}
videojs.registerPlugin('myPlugin', MyPlugin);
player.myPlugin(); Defensive patterns
Strategy: type-guard
Validate before calling
function instantiatePlugin(Klass, player) {
const Base = videojs.getPlugin('plugin');
if (Klass === Base) throw new TypeError('instantiate a Plugin subclass, not the base');
return new Klass(player);
} Type guard
const isPluginSubclass = (K) =>
typeof K === 'function' && K !== videojs.getPlugin('plugin') &&
videojs.getPlugin('plugin').prototype.isPrototypeOf(K.prototype); Prevention
- Always extend videojs.getPlugin('plugin').
- Register subclasses and invoke via player.myPlugin(), not new.
- Use registerPlugin(name, fn) for basic (function) plugins.
When it happens
Trigger: Calling new videojs.getPlugin('plugin')(player); mistakenly instantiating the base Plugin returned by registerPlugin or getPlugin('plugin').
Common situations: Confusing getPlugin('plugin') (the base class) with a named plugin; copy-paste from docs that show Plugin extension without the extends clause; SSR/inspection code that tries to instantiate every plugin.
Related errors
- plugin "${name}" does not exist
- Illegal plugin name, "${name}", must be a string, was ${type
- Illegal plugin name, "${name}", cannot share a name with an
- Illegal plugin for "${name}", must be a function, was ${type
- Cannot de-register base plugin.
AI-assisted analysis of videojs/video.js@c3a7e0e6d2 (2026-08-13).
Data as JSON: /api/errors/d207425755c7e77c.
Report an issue: GitHub.