skip to Main Content

The following code sometimes throws an exception in Firefox:

try {
  videoElem.load();
} 
catch (ignored) {}

The error:

Uncaught (in promise) DOMException: The fetching process for the media resource was aborted by the user agent at the user’s request.

I think it has to do with Firefox not loading the video when the page is not visible, to save resources. This makes sense, but I would like to catch the exception and continue executing my code.

The statement is already in a try catch, but still the exception is uncaught. load() does not return a promise. How do I catch this error?

2

Answers


  1. This looks like a Firefox bug.

    I can repro this: first use a slow network to load a video. While the video is still loading, click the play icon from the <video>‘s controls UI. Then execute OP’s code.

    This suggests to me that the culprit is that UI, which probably does call an equivalent of HTMLMediaElement.prototype.play() on the video element, but doesn’t catch in case there was an error.

    There is no way (I know of) to capture the actual click event on that UI. However listening for the play event brings us right in the good place, might be useful depending on how you plan to act on that issue.

    We can actually catch that rejection, by listening for the global unhandledrejection event, but unlike other such events, preventing this one does not prevent its message being displayed in the console… And I couldn’t find another way to do so, short of not calling load() when the networkState is NETWORK_LOADING, but that’s probably not what you want.

    We can also detect that this happened by listening to the abort event, which would also fire in other browsers in such circumstances.

    const vid = document.querySelector("video");
    
    vid.addEventListener("play",  (evt) => {
      vid.load();
    }, { once: true });
    
    // Catch it like any other unhandled promise rejection
    addEventListener("unhandledrejection", (evt) => {
      console.log(evt.reason);
      evt.preventDefault(); // does not prevent the message in the console...
    });
    
    // We can also know that something went bad from here
    vid.addEventListener("abort", e => console.log("aborted"));
    <h4>Click the play icon of the below &lt;video> in less than 5s</h4>
    <video controls>
      <source src="https://app.requestly.io/delay/5000/https://upload.wikimedia.org/wikipedia/commons/a/a4/BBH_gravitational_lensing_of_gw150914.webm?">
    </video>

    Arguably, it might still be useful to have that error message in the console, since something didn’t go well, but being able to catch it in the unhandledrejection while not being able to prevent the error message seems wrong, so you might want to open an issue.

    Login or Signup to reply.
  2. You can actually get all unhandled errors if you initialize the error event handler beforehand in the window/(i)frame. Even those that happen in promises.

    const errorHandler = errorEvent =>
    {
      // Contains the actual error object.
      const errorObject = errorEvent?.error;
    
      // Contains the error message.
      const errorMessage = errorObject?.message ?? errorEvent?.message ?? errorEvent?.reason;
    
      // Contains the error stack trace if available.
      const errorStack = errorObject?.stack ?? errorEvent?.stack;
    
      console.warn
      (
        'Error caught:',
        {
          Message: errorMessage,
          Stack: errorStack,
        }
      );
    }
    
    addEventListener('error', errorHandler);
    addEventListener('unhandledrejection', errorHandler);
    
    console.clear();
    
    // TEST 1 \
    new Promise
    (
      ( resolve, reject ) =>
      {
        setTimeout(() => reject('The promise was rejected!'), 500);
      }
    );
    
    // TEST 2 \
    new Promise
    (
      ( resolve, reject ) =>
      {
        setTimeout(() => reject(window[Symbol()]()), 500);
      }
    );

    NOTE that this must be initialized before any error might happen. If there’s more scripts in the page that can throw unhandled exceptions, make sure they’re run after the event listener implementation. Sometimes applying the defer property to other <link> or <script> tags that are not the initializer can help.

    See more details in this other answer here:
    https://stackoverflow.com/a/79184566/2804429

    HINT: Look for the messages in the browser console instead of the snippet console there.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search