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

  1. Make your tech class extend Tech: import { Tech } from 'video.js'; class MyTech extends Tech { ... }
  2. Register the class (not an instance) unless isTech also matches instances of a Tech subclass.
  3. 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

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


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