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
- 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.
- Ensure the resource server sends Access-Control-Allow-Origin matching the page origin (and Access-Control-Allow-Credentials if withCredentials is used).
- Host the resource same-origin to sidestep CORS entirely.
- Race the fetch promise against a timeout so a hanging promise cannot stall the UI (the library's reject never fires).
- 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
- Serve VTT/caption/thumbnail assets from the same origin as the page to avoid the CORS 'error' path entirely.
- For cross-origin assets, confirm the response includes Access-Control-Allow-Origin in the Network tab before relying on it.
- Always race fetch promises against a timeout since the library's reject path is broken.
- Watch the console for the uncaught 'Error: 0' — it is the signature of this code path firing.
- If you vendor/fork the library, patch the 'error' listener to call reject(new Error(...)) with a descriptive message.
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.