sampotts/plyr · error · Error

request.status

Error message

request.status

What it means

This is the fetch() XHR wrapper's network-error path. It runs only when XMLHttpRequest fires its 'error' event (network-level failure: CORS rejection, DNS failure, connection refused, offline, mixed-content blocking) — NOT for HTTP 4xx/5xx, which fire 'load'. The handler is defective: it throws synchronously inside an async event callback, so the throw escapes the Promise constructor's try/catch. Consequence: the returned promise is never rejected (it hangs forever) and the throw becomes an uncaught global exception. Additionally, request.status on a network 'error' is a number (commonly 0), so new Error(request.status) yields the unhelpful message '0'.

Source

Thrown at src/js/utils/fetch.js:34

        request.withCredentials = true;
      }

      request.addEventListener('load', () => {
        if (responseType === 'text') {
          try {
            resolve(JSON.parse(request.responseText));
          }
          catch {
            resolve(request.responseText);
          }
        }
        else {
          resolve(request.response);
        }
      });

      request.addEventListener('error', () => {
        throw new Error(request.status);
      });

      request.open('GET', url, true);
      request.responseType = responseType;
      request.send();
    }
    catch (error) {
      reject(error);
    }
  });
}

View on GitHub (pinned to 6520022413)

Solutions

  1. Open DevTools Network tab, find the failing request, and read the real cause (status '(failed)', CORS error, blocked:mixed-content) — then fix the underlying reachability/CORS issue.
  2. Ensure the resource server sends Access-Control-Allow-Origin matching the page origin (and Access-Control-Allow-Credentials if withCredentials is used).
  3. Host the resource same-origin to sidestep CORS entirely.
  4. Race the fetch promise against a timeout so a hanging promise cannot stall the UI (the library's reject never fires).
  5. If you maintain this code, patch the handler to call reject(new Error(...)) with a descriptive message instead of throw.

Example fix

// before (library, buggy)
request.addEventListener('error', () => {
  throw new Error(request.status);
});

// after (patched)
request.addEventListener('error', () => {
  reject(new Error(`Network request failed for ${url} (status: ${request.status})`));
});
Defensive patterns

Strategy: validation

Validate before calling

// Because the library's error handler is buggy (it throws instead of reject,
// leaving the promise pending forever), the robust defense is to pre-check the
// URL and to race the call against a timeout so the UI never stalls.
function safeFetch(url, responseType, withCredentials, timeoutMs = 8000) {
  // Cheap static checks before issuing the request
  try {
    const u = new URL(url, window.location.href);
    if (window.location.protocol === 'https:' && u.protocol === 'http:') {
      return Promise.reject(new Error(`Mixed content blocked: ${url}`));
    }
  } catch {
    return Promise.reject(new Error(`Invalid URL: ${url}`));
  }

  return Promise.race([
    fetch(url, responseType, withCredentials),
    new Promise((_, reject) =>
      setTimeout(() => reject(new Error(`fetch timed out after ${timeoutMs}ms: ${url}`)), timeoutMs)
    )
  ]);
}

Type guard

// Narrow a URL to same-origin, where CORS cannot trigger the 'error' path.
function isSameOrigin(url) {
  try {
    const u = new URL(url, window.location.href);
    return u.origin === window.location.origin;
  } catch {
    return false;
  }
}

// Use a same-origin endpoint for thumbnails/captions whenever possible:
if (!isSameOrigin(thumbnailUrl)) {
  console.warn('Cross-origin resource; ensure CORS headers are present:', thumbnailUrl);
}

Try / catch

// NOTE: the library never rejects on network failure, so .catch() alone will NOT
// fire. Wrap the call in a timeout race (see validationCode) so you actually get
// a rejection to handle. Then:
safeFetch(vttUrl, 'text', false)
  .then(text => parseVtt(text))
  .catch(err => {
    // err.message tells you whether it was timeout, mixed-content, or invalid URL
    console.warn('Thumbnail load failed, continuing without previews:', err.message);
    return null;
  });

Prevention

When it happens

Trigger: Any internal fetch(url, ...) call (VTT thumbnails, captions, etc.) whose request fails at the network layer: the 'error' event fires. Typical causes are cross-origin resources lacking Access-Control-Allow-Origin, offline/no connectivity, DNS resolution failure, connection refused, or mixed http/https content being blocked by the browser.

Common situations: Serving thumbnail VTT or caption files from a CDN/different origin without CORS headers; developing while offline; a CDN outage or typo'd host in the resource URL; HTTP resources referenced from an HTTPS page (mixed content); aggressive ad-blockers/firewalls dropping the sub-resource request.


AI-assisted analysis of sampotts/plyr@6520022413 (2026-08-13). Data as JSON: /api/errors/891c12cb2c88fec0. Report an issue: GitHub.