videojs/video.js · error · Error
Tech ${name} must be a Tech
Error message
Tech ${name} must be a Tech What it means
Thrown by Tech.registerTech(name, tech) when Tech.isTech(tech) returns false. isTech accepts a class whose prototype chain includes Tech, a Tech instance, or the Tech class itself. The guard prevents registering an arbitrary object/function as a playback tech, which would break tech resolution in the player.
Source
Thrown at src/js/tech/tech.js:1018
component === Tech;
}
/**
* Registers a `Tech` into a shared list for videojs.
*
* @param {string} name
* Name of the `Tech` to register.
*
* @param {Object} tech
* The `Tech` class to register.
*/
static registerTech(name, tech) {
if (!Tech.techs_) {
Tech.techs_ = {};
}
if (!Tech.isTech(tech)) {
throw new Error(`Tech ${name} must be a Tech`);
}
if (!Tech.canPlayType) {
throw new Error('Techs must have a static canPlayType method on them');
}
if (!Tech.canPlaySource) {
throw new Error('Techs must have a static canPlaySource method on them');
}
name = toTitleCase(name);
Tech.techs_[name] = tech;
Tech.techs_[toLowerCase(name)] = tech;
if (name !== 'Tech') {
// camel case the techName for use in techOrder
Tech.defaultTechOrder_.push(name);
}
return tech;View on GitHub (pinned to c3a7e0e6d2)
Solutions
- Make your tech class extend Tech: import { Tech } from 'video.js'; class MyTech extends Tech { ... }
- Register the class (not an instance) unless isTech also matches instances of a Tech subclass.
- Confirm the transpiled output preserves the prototype chain (check MyTech.prototype instanceof videojs.getTech('Tech')).
Example fix
// before
class FlashLike {}
videojs.registerTech('FlashLike', FlashLike);
// after
import { Tech } from 'video.js';
class FlashLike extends Tech {}
videojs.registerTech('FlashLike', FlashLike); Defensive patterns
Strategy: type-guard
Validate before calling
function registerTechSafe(name, tech) {
const Tech = videojs.getTech('Tech');
if (!Tech.isTech(tech)) {
throw new TypeError(`${name} must be a class extending Tech`);
}
videojs.registerTech(name, tech);
} Type guard
function isTechClass(tech) {
const Tech = videojs.getTech('Tech');
return Tech.isTech(tech);
} Try / catch
try {
videojs.registerTech(name, tech);
} catch (err) {
if (/must be a Tech/.test(err.message)) {
console.error(`${name} does not extend videojs.Tech; registration skipped.`);
} else { throw err; }
} Prevention
- Always extend videojs.Tech when authoring a custom tech.
- Call videojs.Tech.isTech(MyTech) in your test suite before registerTech.
- Register the class, not an instance, unless isTech matches instances.
When it happens
Trigger: Calling videojs.registerTech('MyTech', PlainFunction) where PlainFunction does not extend Tech; passing a plain options object instead of a class; passing a source-handler module or a plugin constructor by mistake.
Common situations: Writing a custom playback tech and forgetting to extend the base Tech class; copying a plugin-style definition into registerTech; bundler/tree-shaking or transpilation that breaks the ES6 extends prototype chain (e.g. Babel loose mode without the inherits helper).
Related errors
- Techs must have a static canPlayType method on them
- Techs must have a static canPlaySource method on them
- A tech was not provided.
- Illegal component, "${name}"; ${reason}.
- No techOrder specified. Did you overwrite videojs.options in
AI-assisted analysis of videojs/video.js@c3a7e0e6d2 (2026-08-13).
Data as JSON: /api/errors/304fe38d0418d8f4.
Report an issue: GitHub.