DOMException: The play() request was interrupted
Did you just stumble upon this unexpected media error in the Chrome DevTools JavaScript Console?
Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause().
or
Uncaught (in promise) DOMException: The play() request was interrupted by a load request.
You're in the right place then. Have no fear. I'll explain what is causing this and how to fix it.
What is causing this
Here's some JavaScript code below that reproduces the "Uncaught (in promise)" error you're seeing:
DON'T
<video id="video" preload="none" src="https://example.com/file.mp4"></video>
<script>
video.play(); // <-- This is asynchronous!
video.pause();
</script>
The code above results in this error message in Chrome DevTools:
Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause().
As the video is not loaded due to preload="none"
, video playback doesn't
necessarily start immediately after video.play()
is executed.
Moreover since Chrome 50, a play()
call on an a <video>
or <audio>
element returns a Promise, a function that returns a single result
asynchronously. If playback succeeds, the Promise is fulfilled, and if playback
fails, the Promise is rejected along with an error message explaining the
failure.
Now here's what happening:
video.play()
starts loading video content asynchronously.video.pause()
interrupts video loading because it is not ready yet.video.play()
rejects asynchronously loudly.
Since we're not handling the video play Promise in our code, an error message appears in Chrome DevTools.
Note: Calling video.pause()
isn't the only way to interrupt a video "play()"
request. You can reset entirely video playback state, including buffer with
video.load()
and video.src = ''
.
How to fix it
Now that we understand the root cause, let's see what we can do to fix this properly.
First, don't ever assume a media element (video or audio) will play. Look at
the Promise returned by the play
function to see if it was rejected. It is
worth noting that the Promise won't fulfill until playback has actually
started, meaning the code inside the then()
will not execute until the media
is playing.
Example: Autoplay
<video id="video" preload="none" src="https://example.com/file.mp4"></video>
<script>
var playPromise = video.play();
if (playPromise !== undefined) {
playPromise.then(_ => {
// Automatic playback started!
})
.catch(error => {
// Auto-play was prevented
// Show a UI element to let the user manually start playback
});
}
</script>
Example: Play & Pause
<video id="video" preload="none" src="https://example.com/file.mp4"></video> <script> var playPromise = video.play(); if (playPromise !== undefined) { playPromise.then(_ => { // Automatic playback started! // We can now safely pause video... video.pause(); }) .catch(error => { // Auto-play was prevented // Show a UI element to let the user manually start playback }); } </script>
That's great for this simple example but what if you use video.play()
to be
able to play a video later when user interacts with the website you may think?
I'll tell you a secret... you don't have to use video.play()
, you can use
video.load()
and here's how:
Example: Fetch & Play
<video id="video"></video>
<button id="button"></button>
<script>
button.addEventListener('click', onButtonClick);
function onButtonClick() {
// This will allow us to play video later...
video.load();
fetchVideoAndPlay();
}
function fetchVideoAndPlay() {
fetch('https://example.com/file.mp4')
.then(response => response.blob())
.then(blob => {
video.srcObject = blob;
return video.play();
})
.then(_ => {
// Video playback started ;)
})
.catch(e => {
// Video playback failed ;(
})
}
</script>
Warning: Don't make your onButtonClick
function asynchronous with the async
keyword for instance. You'll lose the "user gesture token" required to allow
your video to play later.
Play promise support
At the time of writing, HTMLMediaElement.play()
returns a promise in
Chrome, Firefox, Opera, and Safari. Edge is still working on it.