videojs/video.js · critical · Error

No techOrder specified. Did you overwrite videojs.options in

Error message

No techOrder specified. Did you overwrite videojs.options instead of just changing the properties you want to override?

What it means

On player construction video.js reads this.options_.techOrder (the list of playback technologies to try, e.g. ['html5','flash']). If options_ itself, techOrder, or its length is missing, the global videojs.options was almost certainly overwritten instead of merged, which would make playback impossible. The error message points at the most common cause directly.

Source

Thrown at src/js/player.js:423

    // Init state audioOnlyMode_
    this.audioOnlyMode_ = false;

    // Init state audioPosterMode_
    this.audioPosterMode_ = false;

    // Init state audioOnlyCache_
    this.audioOnlyCache_ = {
      controlBarHeight: null,
      playerHeight: null,
      hiddenChildren: []
    };

    // if the global option object was accidentally blown away by
    // someone, bail early with an informative error
    if (!this.options_ ||
        !this.options_.techOrder ||
        !this.options_.techOrder.length) {
      throw new Error('No techOrder specified. Did you overwrite ' +
                      'videojs.options instead of just changing the ' +
                      'properties you want to override?');
    }

    // Store the original tag used to set options
    this.tag = tag;

    // Store the tag attributes used to restore html5 element
    this.tagAttributes = tag && Dom.getAttributes(tag);

    // Update current language
    this.language(this.options_.language);

    // Update Supported Languages
    if (options.languages) {
      // Normalise player option languages to lowercase
      const languagesToLower = {};

View on GitHub (pinned to c3a7e0e6d2)

Solutions

  1. Mutate individual properties: videojs.options.controls = true; videojs.options.techOrder = ['html5'];
  2. Merge instead of replace: Object.assign(videojs.options, myConfig) or videojs.options = {...videojs.options, ...myConfig}.
  3. Pass options per-instance: videojs('vid', {techOrder: ['html5'], ...}).

Example fix

// before
videojs.options = { controls: true }; // wipes techOrder
// after
videojs.options.controls = true;
// or merge
videojs.options = { ...videojs.options, controls: true };
Defensive patterns

Strategy: validation

Validate before calling

function mergeVideojsOptions(patch) {
  if (!videojs.options.techOrder) {
    throw new Error('refusing to apply patch: techOrder missing');
  }
  Object.assign(videojs.options, patch);
}

Type guard

const hasTechOrder = (o) =>
  o && Array.isArray(o.techOrder) && o.techOrder.length > 0;

Prevention

When it happens

Trigger: Doing videojs.options = {controls: true} (replacing the object) instead of videojs.options.controls = true; passing {techOrder: undefined} explicitly; a plugin that assigns over videojs.options.

Common situations: Tutorial code that reassigns videojs.options; SSR or build setups that mutate the global; integrating video.js with a config layer that wholesale replaces rather than merges.

Related errors


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