{"record":{"id":"3226d51f02b0c3b3","repo":"videojs/video.js","slug":"rejection-at-manualautoplay-restoring-muted-value","errorCode":null,"errorMessage":"Rejection at manualAutoplay. Restoring muted value. ${err ? err : ''}","messagePattern":"Rejection at manualAutoplay\\. Restoring muted value\\. (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/js/player.js","lineNumber":1535,"sourceCode":"\n      this.muted(true);\n\n      const restoreMuted = () => {\n        this.muted(previouslyMuted);\n      };\n\n      // restore muted on play terminatation\n      this.playTerminatedQueue_.push(restoreMuted);\n\n      const mutedPromise = this.play();\n\n      if (!isPromise(mutedPromise)) {\n        return;\n      }\n\n      return mutedPromise.catch(err => {\n        restoreMuted();\n        throw new Error(`Rejection at manualAutoplay. Restoring muted value. ${err ? err : ''}`);\n      });\n    };\n\n    let promise;\n\n    // if muted defaults to true\n    // the only thing we can do is call play\n    if (type === 'any' && !this.muted()) {\n      promise = this.play();\n\n      if (isPromise(promise)) {\n        promise = promise.catch(resolveMuted);\n      }\n    } else if (type === 'muted' && !this.muted()) {\n      promise = resolveMuted();\n    } else {\n      promise = this.play();\n    }","sourceCodeStart":1517,"sourceCodeEnd":1553,"githubUrl":"https://github.com/videojs/video.js/blob/c3a7e0e6d20cf5400c9afbee29965fe4dff393c2/src/js/player.js#L1517-L1553","documentation":"During the muted-autoplay fallback path, video.js calls play() while temporarily unmuting; if that play() promise rejects (browser autoplay policy), it restores the original muted value and rethrows wrapped in this message. The error is informational — the player returns to its prior state — but it surfaces the rejection so callers can react.","triggerScenarios":"Browser blocks muted autoplay (rare) or unmuted-after-mute autoplay; calling player.autoplay('muted') or 'any' in a browser with strict autoplay policy and low engagement; play() rejecting for a media-error reason during the fallback.","commonSituations":"Mobile Safari/Chrome autoplay restrictions; iframe without allow='autoplay'; muted state changed by another caller mid-flight; media decode error surfacing through the play promise.","solutions":["Catch the rejection at the call site: const p = player.play(); if (p) p.catch(() => {/* show play button */});","Ensure the media element is actually muted before relying on muted autoplay, and the iframe has allow='autoplay'.","Provide a visible play button UI as a fallback when autoplay is blocked."],"exampleFix":"// before\nplayer.autoplay('any'); // uncaught rejection possible\n// after\nplayer.autoplay('any');\nplayer.on('autoplayfailure', () => showPlayButton());","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"const isPlayPromise = (p) => p && typeof p.then === 'function';","tryCatchPattern":"const p = player.play();\nif (p && typeof p.then === 'function') {\n  p.catch((err) => {\n    showPlayButton();\n    player.log('autoplay blocked:', err);\n  });\n}","preventionTips":["Listen for the 'autoplayfailure' event to drive fallback UI.","Ensure iframes carry allow='autoplay'.","Prefer muted autoplay for mobile; surface a play button otherwise."],"tags":["player","autoplay","promise","browser-policy"],"backgroundTag":null,"analyzedSha":"c3a7e0e6d20cf5400c9afbee29965fe4dff393c2","analyzedAt":"2026-08-13T04:20:15.471Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}