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
- Mutate individual properties: videojs.options.controls = true; videojs.options.techOrder = ['html5'];
- Merge instead of replace: Object.assign(videojs.options, myConfig) or videojs.options = {...videojs.options, ...myConfig}.
- 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
- Never reassign videojs.options; mutate or merge it.
- Pass techOrder per-instance in videojs('id', {techOrder: [...]}).
- Add a smoke-test asserting videojs.options.techOrder length.
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
- Component ${componentClassName} does not exist
- plugin "${name}" does not exist
- Improper value supplied for aspect ratio. The format should
- No Tech named '${titleTechName}' exists! '${titleTechName}'
- Illegal component, "${name}"; ${reason}.
AI-assisted analysis of videojs/video.js@c3a7e0e6d2 (2026-08-13).
Data as JSON: /api/errors/62da8933cffa0624.
Report an issue: GitHub.