videojs/video.js · error · Error

A tech was not provided.

Error message

A tech was not provided.

What it means

Thrown by the TextTrack constructor when options.tech is missing. A TextTrack is tightly coupled to its owning Tech for cue rendering, event dispatch, and track-list management; without a tech reference it cannot function. The constructor defaults options to {} and immediately checks the tech key.

Source

Thrown at src/js/tracks/text-track.js:164

   * @param {string} [options.label='']
   *        The menu label for this track.
   *
   * @param {string} [options.language='']
   *        A valid two character language code.
   *
   * @param {string} [options.srclang='']
   *        A valid two character language code. An alternative, but deprioritized
   *        version of `options.language`
   *
   * @param {string} [options.src]
   *        A url to TextTrack cues.
   *
   * @param {boolean} [options.default]
   *        If this track should default to on or off.
   */
  constructor(options = {}) {
    if (!options.tech) {
      throw new Error('A tech was not provided.');
    }

    const settings = merge(options, {
      kind: TextTrackKind[options.kind] || 'subtitles',
      language: options.language || options.srclang || ''
    });
    let mode = TextTrackMode[settings.mode] || 'disabled';
    const default_ = settings.default;

    if (settings.kind === 'metadata' || settings.kind === 'chapters') {
      mode = 'hidden';
    }
    super(settings);

    this.tech_ = settings.tech;

    this.cues_ = [];
    this.activeCues_ = [];

View on GitHub (pinned to c3a7e0e6d2)

Solutions

  1. Prefer player.addTextTrack() / addRemoteTextTrack(), which supply the tech automatically.
  2. If constructing manually, pass the owning tech: new TextTrack({ ..., tech: player.tech_ }).
  3. Ensure the options object is built from a source that always includes a tech reference.

Example fix

// before
new TextTrack({ kind: 'subtitles', label: 'English' });
// after
new TextTrack({ kind: 'subtitles', label: 'English', tech: player.tech_ });
Defensive patterns

Strategy: validation

Validate before calling

function safeNewTextTrack(options) {
  if (!options || !options.tech) {
    throw new TypeError('TextTrack requires options.tech');
  }
  return new videojs.TextTrack(options);
}

Type guard

function hasTechRef(options) {
  return !!options && !!options.tech;
}

Try / catch

try {
  return new videojs.TextTrack(options);
} catch (err) {
  if (/tech was not provided/.test(err.message)) {
    options = { ...options, tech: player.tech_ };
    return new videojs.TextTrack(options);
  }
  throw err;
}

Prevention

When it happens

Trigger: Constructing 'new TextTrack({ kind: "subtitles", label: "en" })' with no tech; passing an options object missing the 'tech' key; instantiating TextTrack in a custom component instead of going through the player/tech track APIs.

Common situations: Directly instantiating TextTrack in tests or custom components rather than using player.addTextTrack / player.addRemoteTextTrack (which inject the tech automatically); a refactor that drops the tech reference from the options object.

Related errors


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