5.1 KiB
Error Handling & Resilience Guide
Strategies, error classification, and recovery patterns for handling network stalls, upstream rate limits, and streaming failures.
Overview
Streaming from distributed upstream web providers is inherently dynamic. Upstream CDN nodes rotate domains, regional ISPs implement traffic shaping, and token signatures expire.
Building a resilient client requires planning for failure at every step. This guide explains how Vyla handles errors internally and how client players should respond.
Error Classification Matrix
| Error Type | Common Cause | Stream API / SDK Behavior | Recommended Player Action |
|---|---|---|---|
| HTTP 400 Bad Request | Missing or malformed TMDB ID, invalid season/episode | Returns immediate JSON error payload without querying providers. | Validate input parameters client-side before sending requests. |
| HTTP 429 Too Many Requests | Upstream host rate-limiting client IP | SDK provider applies backoff delay and retries up to retries limit. |
If proxy returns 429, respect the retry_after header and back off. |
| HTTP 502 Bad Gateway | Upstream provider host is unreachable or timed out | Provider is discarded; other scrapers continue executing. | Fall back to the next available stream candidate in your queue. |
| SSE Disconnect | Network hiccup or client tab backgrounded | Connection drops; EventSource.onerror fires. |
If video is already playing, do not interrupt. Otherwise, reconnect after 2 seconds. |
| HLS Fatal Media Error | Segment buffer stall, corrupt chunk, or missing decryption key | Player triggers Hls.Events.ERROR with fatal: true. |
Call hls.destroy() and load the next candidate from your fallback queue. |
Client Fallback Queue Strategy
Always treat streaming candidate resolution as a prioritized queue rather than a single static link:
Queue Priority Assignment
| Candidate Stream | Player State | Fallback Precedence |
|---|---|---|
Candidate 1 (vidlink) |
Active Playback | Mounted into HLS.js or ExoPlayer on arrival. |
Candidate 2 (vixsrc) |
Standby Backup | Enqueued as Priority #1 fallback stream. |
Candidate 3 (cinecat) |
Standby Backup | Enqueued as Priority #2 fallback stream. |
Recovery Sequence on Stream Stall
- Error Interception: Player detects a fatal network or decode event (
data.fatal === true). - Timestamp Preservation: Record current playback offset (e.g.
currentTime = 142.5s). - Buffer Teardown: Call
hls.destroy()orplayer.release()to release media pipelines and decoders. - Queue Advancement: Dequeue the next available verified candidate from the standby queue.
- Seamless Seek: Mount the fallback source and seek immediately to the preserved timestamp upon
loadedmetadata.
Implementing Fallback Recovery in JavaScript
function attachHlsPlayer(videoElement, candidate, fallbackQueue) {
const hls = new Hls({
maxBufferLength: 30,
maxMaxBufferLength: 60,
enableWorker: true
});
hls.loadSource(candidate.url);
hls.attachMedia(videoElement);
hls.on(Hls.Events.ERROR, (event, data) => {
if (!data.fatal) return;
console.warn(`Encountered fatal error on ${candidate.source}:`, data.type);
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
console.log("Attempting network recovery...");
hls.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.log("Attempting media recovery...");
hls.recoverMediaError();
break;
default:
hls.destroy();
if (fallbackQueue.length > 0) {
const nextCandidate = fallbackQueue.shift();
const lastTime = videoElement.currentTime;
console.warn(`Switching to fallback candidate: ${nextCandidate.label}`);
attachHlsPlayer(videoElement, nextCandidate, fallbackQueue);
videoElement.addEventListener('loadedmetadata', () => {
videoElement.currentTime = lastTime;
videoElement.play();
}, { once: true });
} else {
showErrorOverlay("All available streaming providers have failed.");
}
break;
}
});
return hls;
}
Client-Side Timeout Budgets
Never leave users hanging on an indefinite spinner. Implement a two-tiered timeout budget:
- Initial Candidate Timeout (8–10 seconds): If no
type: "source"event has arrived within 8 seconds, update the UI to indicate extended searching. - Hard Timeout (20 seconds): If the stream has not completed or emitted a viable candidate within 20 seconds:
- Call
eventSource.close(). - Render a helpful empty-state UI with a "Retry" button or an option to change the server URL.
- Call
Decoupled Subtitle Fallback
Subtitles originate from independent subtitle repositories (e.g. OpenSubtitles, SubDL). If a subtitle track fails to load:
- The video playback must continue uninterrupted.
- Log a warning in the console.
- Offer the viewer an in-player menu to toggle alternative subtitle providers or upload a local
.srt/.vttfile.