HLS.js provides comprehensive error handling with detailed error types, automatic recovery mechanisms, and configurable retry logic.
All errors are reported through the ERROR event with detailed information.
hls.on(Hls.Events.ERROR, (event, data: ErrorData) => {
// Handle error based on type and severity
});
interface ErrorData {
/** Error category */
type: ErrorTypes;
/** Specific error details */
details: ErrorDetails;
/** Whether error is fatal (stops playback) */
fatal: boolean;
/** Human-readable error reason */
reason?: string;
/** Associated quality level */
level?: number;
/** Associated fragment */
frag?: Fragment;
/** Failed URL */
url?: string;
/** HTTP response object */
response?: Response;
/** Additional context */
context?: any;
/** Error handling action taken */
action?: NetworkErrorAction;
/** Retry count */
retryCount?: number;
/** Internal error object */
error?: Error;
}Usage Example:
const hls = new Hls();
hls.on(Hls.Events.ERROR, (event, data) => {
console.error(`HLS Error: ${data.type} - ${data.details}`);
console.error(`Fatal: ${data.fatal}, Reason: ${data.reason}`);
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
console.error("Network error, try to recover");
hls.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.error("Media error, try to recover");
hls.recoverMediaError();
break;
default:
console.error("Fatal error, cannot recover");
hls.destroy();
break;
}
}
});Categories of errors that can occur.
enum ErrorTypes {
/** Network loading and timeout errors */
NETWORK_ERROR = "networkError",
/** Video/audio parsing and MediaSource errors */
MEDIA_ERROR = "mediaError",
/** DRM and EME errors */
KEY_SYSTEM_ERROR = "keySystemError",
/** Demuxing and remuxing errors */
MUX_ERROR = "muxError",
/** All other errors */
OTHER_ERROR = "otherError"
}Specific error details with over 50 different error types.
enum ErrorDetails {
// Key system/DRM errors
KEY_SYSTEM_NO_KEYS = "keySystemNoKeys",
KEY_SYSTEM_NO_ACCESS = "keySystemNoAccess",
KEY_SYSTEM_NO_SESSION = "keySystemNoSession",
KEY_SYSTEM_NO_CONFIGURED_LICENSE = "keySystemNoConfiguredLicense",
KEY_SYSTEM_LICENSE_REQUEST_FAILED = "keySystemLicenseRequestFailed",
KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED = "keySystemServerCertificateRequestFailed",
KEY_SYSTEM_SERVER_CERTIFICATE_UPDATE_FAILED = "keySystemServerCertificateUpdateFailed",
KEY_SYSTEM_SESSION_UPDATE_FAILED = "keySystemSessionUpdateFailed",
KEY_SYSTEM_STATUS_OUTPUT_RESTRICTED = "keySystemStatusOutputRestricted",
KEY_SYSTEM_STATUS_INTERNAL_ERROR = "keySystemStatusInternalError",
KEY_SYSTEM_DESTROY_MEDIA_KEYS_ERROR = "keySystemDestroyMediaKeysError",
KEY_SYSTEM_DESTROY_CLOSE_SESSION_ERROR = "keySystemDestroyCloseSessionError",
KEY_SYSTEM_DESTROY_REMOVE_SESSION_ERROR = "keySystemDestroyRemoveSessionError",
// Manifest errors
MANIFEST_LOAD_ERROR = "manifestLoadError",
MANIFEST_LOAD_TIMEOUT = "manifestLoadTimeOut",
MANIFEST_PARSING_ERROR = "manifestParsingError",
MANIFEST_INCOMPATIBLE_CODECS_ERROR = "manifestIncompatibleCodecsError",
// Level errors
LEVEL_EMPTY_ERROR = "levelEmptyError",
LEVEL_LOAD_ERROR = "levelLoadError",
LEVEL_LOAD_TIMEOUT = "levelLoadTimeOut",
LEVEL_PARSING_ERROR = "levelParsingError",
LEVEL_SWITCH_ERROR = "levelSwitchError",
// Audio track errors
AUDIO_TRACK_LOAD_ERROR = "audioTrackLoadError",
AUDIO_TRACK_LOAD_TIMEOUT = "audioTrackLoadTimeOut",
// Subtitle track errors
SUBTITLE_LOAD_ERROR = "subtitleTrackLoadError",
SUBTITLE_TRACK_LOAD_TIMEOUT = "subtitleTrackLoadTimeOut",
// Fragment errors
FRAG_LOAD_ERROR = "fragLoadError",
FRAG_LOAD_TIMEOUT = "fragLoadTimeOut",
FRAG_DECRYPT_ERROR = "fragDecryptError",
FRAG_PARSING_ERROR = "fragParsingError",
FRAG_GAP = "fragGap",
// Remux errors
REMUX_ALLOC_ERROR = "remuxAllocError",
// Key loading errors
KEY_LOAD_ERROR = "keyLoadError",
KEY_LOAD_TIMEOUT = "keyLoadTimeOut",
// Buffer errors
BUFFER_ADD_CODEC_ERROR = "bufferAddCodecError",
BUFFER_INCOMPATIBLE_CODECS_ERROR = "bufferIncompatibleCodecsError",
BUFFER_APPEND_ERROR = "bufferAppendError",
BUFFER_APPENDING_ERROR = "bufferAppendingError",
BUFFER_STALLED_ERROR = "bufferStalledError",
BUFFER_FULL_ERROR = "bufferFullError",
BUFFER_SEEK_OVER_HOLE = "bufferSeekOverHole",
BUFFER_NUDGE_ON_STALL = "bufferNudgeOnStall",
// Interstitial/asset errors
ASSET_LIST_LOAD_ERROR = "assetListLoadError",
ASSET_LIST_LOAD_TIMEOUT = "assetListLoadTimeout",
ASSET_LIST_PARSING_ERROR = "assetListParsingError",
INTERSTITIAL_ASSET_ITEM_ERROR = "interstitialAssetItemError",
// Internal errors
INTERNAL_EXCEPTION = "internalException",
INTERNAL_ABORTED = "aborted",
ATTACH_MEDIA_ERROR = "attachMediaError",
UNKNOWN = "unknown"
}Built-in recovery mechanisms and manual recovery methods.
interface Hls {
/**
* Attempt to recover from media errors
*/
recoverMediaError(): void;
/**
* Swap audio codec and try to recover from media error
*/
swapAudioCodec(): void;
}Usage Examples:
const hls = new Hls();
hls.on(Hls.Events.ERROR, (event, data) => {
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
// Network error recovery
console.log("Network error, restarting load...");
hls.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
// Media error recovery
console.log("Media error, attempting recovery...");
hls.recoverMediaError();
break;
case Hls.ErrorTypes.KEY_SYSTEM_ERROR:
// DRM error - usually fatal
console.error("DRM error, cannot recover");
hls.destroy();
break;
default:
// Other fatal errors
console.error("Fatal error, destroying player");
hls.destroy();
break;
}
} else {
// Non-fatal errors are usually handled automatically
console.warn("Non-fatal error:", data.details);
}
});
// Advanced recovery with retry logic
let mediaErrorRecoveryCount = 0;
const MAX_MEDIA_ERROR_RECOVERY = 3;
hls.on(Hls.Events.ERROR, (event, data) => {
if (data.fatal && data.type === Hls.ErrorTypes.MEDIA_ERROR) {
if (mediaErrorRecoveryCount < MAX_MEDIA_ERROR_RECOVERY) {
mediaErrorRecoveryCount++;
console.log(`Media error recovery attempt ${mediaErrorRecoveryCount}`);
if (mediaErrorRecoveryCount === 1) {
hls.recoverMediaError();
} else if (mediaErrorRecoveryCount === 2) {
hls.swapAudioCodec();
} else {
// Last attempt - full reload
hls.loadSource(hls.url);
}
} else {
console.error("Max media error recovery attempts reached");
hls.destroy();
}
}
});
// Reset recovery count on successful recovery
hls.on(Hls.Events.FRAG_LOADED, () => {
mediaErrorRecoveryCount = 0;
});Configure error handling behavior through HlsConfig.
interface HlsConfig {
// Retry configuration
manifestLoadingMaxRetry: number;
manifestLoadingRetryDelay: number;
levelLoadingMaxRetry: number;
levelLoadingRetryDelay: number;
fragLoadingMaxRetry: number;
fragLoadingRetryDelay: number;
keyLoadingMaxRetry: number;
keyLoadingRetryDelay: number;
// Timeout configuration
manifestLoadingTimeOut: number;
levelLoadingTimeOut: number;
fragLoadingTimeOut: number;
keyLoadingTimeOut: number;
// Error handling options
enableWorker: boolean;
enableSoftwareAES: boolean;
startFragPrefetch: boolean;
ignoreDevicePixelRatio: boolean;
}Usage Example:
const hls = new Hls({
// Increase retry counts
manifestLoadingMaxRetry: 6,
fragLoadingMaxRetry: 6,
// Longer timeouts
manifestLoadingTimeOut: 20000,
fragLoadingTimeOut: 30000,
// Enable fallback options
enableSoftwareAES: true,
enableWorker: true
});Error controller actions for handling network errors.
enum NetworkErrorAction {
DoNothing = 0,
SendEndCallback = 1,
SendAlternateToPenaltyBox = 2,
RemoveAlternatePermanently = 3,
InsertDiscontinuity = 4,
RetryRequest = 5
}
enum ErrorActionFlags {
None = 0,
MoveAllAlternatesMatchingHost = 1,
MoveAllAlternatesMatchingHDCP = 2,
SwitchToSDR = 4
}Create custom error handling logic.
// Custom error handler function
function handleCustomError(hls: Hls, errorData: ErrorData): boolean {
// Return true if error was handled, false to use default handling
if (errorData.details === Hls.ErrorDetails.FRAG_LOAD_ERROR) {
// Custom fragment load error handling
console.log("Custom fragment error handling");
// Try alternative URL or CDN
if (errorData.frag && errorData.response?.status === 404) {
// Switch to backup CDN
return true; // Handled
}
}
return false; // Not handled, use default behavior
}
// Apply custom error handling
hls.on(Hls.Events.ERROR, (event, data) => {
const handled = handleCustomError(hls, data);
if (!handled) {
// Fall back to default error handling
console.log("Using default error handling");
}
});interface Response {
url: string;
status: number;
statusText: string;
headers: Record<string, string>;
}
interface Fragment {
url: string;
byteRange?: ByteRange;
level: number;
sn: number;
start: number;
duration: number;
type: string;
}
interface LoadStats {
aborted: boolean;
loaded: number;
retry: number;
total: number;
chunkCount: number;
bwEstimate: number;
loading: { start: number; first: number; end: number };
parsing: { start: number; end: number };
buffering: { start: number; first: number; end: number };
}