React Native Video provides a comprehensive error handling system with typed error codes, detailed error messages, and error recovery mechanisms.
Error Types
The library defines several categories of errors that can occur during video playback:
Error Categories
- Library Errors - Issues with the video library itself
- Player Errors - Problems with the player instance
- Source Errors - Issues loading or processing the video source
- View Errors - Component-related errors
- Unknown Errors - Unclassified errors
Error Classes
The library provides two main error classes:
VideoRuntimeError
Errors that occur during video playback operations.
import { VideoRuntimeError } from 'react-native-video';
try {
await player.initialize();
} catch (error) {
if (error instanceof VideoRuntimeError) {
console.log('Error code:', error.code);
console.log('Error message:', error.message);
console.log('Stack trace:', error.stack);
}
}
VideoComponentError
Errors related to the video component/view.
import { VideoComponentError } from 'react-native-video';
try {
// Component operations
} catch (error) {
if (error instanceof VideoComponentError) {
console.log('Component error:', error.code);
}
}
Error Codes
All error codes follow a consistent naming pattern: category/specific-error.
Library Errors
The video library has been deallocated and is no longer available.
library/application-context-not-found
Android-specific: The application context could not be found.
Player Errors
The player has been released and can no longer be used.// This will throw player/released error
player.release();
player.play(); // Error: player/released
The player has not been initialized yet.const player = new VideoPlayer({
uri: 'video.mp4',
initializeOnCreation: false
});
// Must initialize first
await player.initialize();
player/asset-not-initialized
The video asset has not been initialized.
The provided video source is invalid.
Source Errors
The video URI is invalid or malformed.// Invalid URI examples
const player1 = new VideoPlayer({ uri: '' }); // Empty
const player2 = new VideoPlayer({ uri: 'not-a-valid-uri' }); // Malformed
source/missing-read-file-permission
The app does not have permission to read the local video file.Ensure your app has proper file system permissions before attempting to load local videos.
source/file-does-not-exist
The specified local video file does not exist.// File doesn't exist
const player = new VideoPlayer({
uri: 'file:///path/to/nonexistent.mp4'
});
source/failed-to-initialize-asset
Failed to initialize the video asset. This can occur due to:
- Corrupted video file
- Unsupported codec
- Network issues
- Insufficient memory
source/unsupported-content-type
The video format or content type is not supported on this platform.
View Errors
The video view component could not be found.
The video view has been deallocated.
view/picture-in-picture-not-supported
Picture-in-picture mode is not supported on this device or platform.
Unknown Errors
An unclassified error occurred. Check the error message for details.
Handling Errors
Using onError Callback
The recommended way to handle errors is through the onError event listener:
import { VideoPlayer } from 'react-native-video';
const player = new VideoPlayer({
uri: 'https://example.com/video.mp4',
});
player.onError = (error) => {
console.log('Error code:', error.code);
console.log('Error message:', error.message);
// Handle specific errors
switch (error.code) {
case 'source/invalid-uri':
// Show user-friendly message
showAlert('Invalid video URL');
break;
case 'source/file-does-not-exist':
// Attempt to reload or use fallback
loadFallbackVideo();
break;
case 'player/not-initialized':
// Initialize and retry
await player.initialize();
break;
default:
// Generic error handling
showAlert('Unable to play video');
}
};
Prevent Error ThrowingWhen an onError callback is provided, the error will not be thrown. This prevents crashes and allows graceful error handling.
Try-Catch Pattern
For async operations, use try-catch blocks:
try {
await player.initialize();
await player.replaceSourceAsync({
uri: 'https://example.com/new-video.mp4',
});
player.play();
} catch (error) {
if (error instanceof VideoRuntimeError) {
handleVideoError(error);
} else {
// Handle unexpected errors
console.error('Unexpected error:', error);
}
}
Error Recovery Patterns
Automatic Retry with Exponential Backoff
async function initializeWithRetry(
player: VideoPlayer,
maxRetries = 3,
initialDelay = 1000
) {
let lastError: Error | null = null;
for (let i = 0; i < maxRetries; i++) {
try {
await player.initialize();
return; // Success
} catch (error) {
lastError = error as Error;
if (error instanceof VideoRuntimeError) {
// Don't retry certain errors
if ([
'source/invalid-uri',
'source/unsupported-content-type',
'player/released'
].includes(error.code)) {
throw error;
}
}
// Wait before retry with exponential backoff
const delay = initialDelay * Math.pow(2, i);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw lastError;
}
// Usage
try {
await initializeWithRetry(player);
player.play();
} catch (error) {
console.error('Failed to initialize after retries:', error);
}
Fallback Source Strategy
const videoSources = [
'https://cdn1.example.com/video.mp4',
'https://cdn2.example.com/video.mp4',
'https://cdn3.example.com/video.mp4',
];
async function loadVideoWithFallback(player: VideoPlayer) {
for (const uri of videoSources) {
try {
await player.replaceSourceAsync({ uri });
await player.initialize();
return; // Success
} catch (error) {
console.log(`Failed to load from ${uri}:`, error);
// Try next source
}
}
throw new Error('All video sources failed to load');
}
Error Recovery Hook
import { useEffect, useState } from 'react';
import { VideoPlayer, VideoRuntimeError } from 'react-native-video';
function useVideoErrorRecovery(player: VideoPlayer) {
const [error, setError] = useState<VideoRuntimeError | null>(null);
const [retryCount, setRetryCount] = useState(0);
useEffect(() => {
player.onError = (error) => {
setError(error);
};
return () => {
player.onError = undefined;
};
}, [player]);
const retry = async () => {
setError(null);
setRetryCount(prev => prev + 1);
try {
await player.initialize();
player.play();
} catch (err) {
// Error will be caught by onError listener
}
};
const reset = () => {
setError(null);
setRetryCount(0);
};
return { error, retryCount, retry, reset };
}
// Usage in component
function VideoComponent() {
const [player] = useState(() => new VideoPlayer({ uri: 'video.mp4' }));
const { error, retryCount, retry, reset } = useVideoErrorRecovery(player);
if (error) {
return (
<View>
<Text>Error: {error.message}</Text>
<Text>Code: {error.code}</Text>
{retryCount < 3 && (
<Button title="Retry" onPress={retry} />
)}
<Button title="Reset" onPress={reset} />
</View>
);
}
return <VideoView player={player} />;
}
Error Logging and Monitoring
Structured Error Logging
function logVideoError(error: VideoRuntimeError, context: Record<string, any>) {
const errorLog = {
timestamp: new Date().toISOString(),
code: error.code,
message: error.message,
stack: error.stack,
context,
};
// Send to analytics service
analytics.logError('video_playback_error', errorLog);
// Log to console in development
if (__DEV__) {
console.error('Video Error:', errorLog);
}
}
// Usage
player.onError = (error) => {
logVideoError(error, {
videoUri: player.source.uri,
playerStatus: player.status,
currentTime: player.currentTime,
platform: Platform.OS,
});
};
Best Practices
Always Provide onError HandlerAlways set up an onError handler to prevent crashes and provide graceful degradation.
Check Error Codes Before RetrySome errors like source/invalid-uri or player/released should not be retried. Check the error code before implementing retry logic.
Provide User FeedbackShow user-friendly error messages instead of raw error codes. Give users actionable options like retry or contact support.
Log Errors for MonitoringImplement error logging to track error patterns and identify systemic issues in production.
Test Error ScenariosTest your error handling with:
- Invalid URIs
- Network failures
- Unsupported formats
- Missing permissions
- Released players
TypeScript Types
type LibraryError =
| 'library/deallocated'
| 'library/application-context-not-found';
type PlayerError =
| 'player/released'
| 'player/not-initialized'
| 'player/asset-not-initialized'
| 'player/invalid-source';
type SourceError =
| 'source/invalid-uri'
| 'source/missing-read-file-permission'
| 'source/file-does-not-exist'
| 'source/failed-to-initialize-asset'
| 'source/unsupported-content-type';
type VideoViewError =
| 'view/not-found'
| 'view/deallocated'
| 'view/picture-in-picture-not-supported';
type UnknownError = 'unknown/unknown';
type VideoErrorCode =
| LibraryError
| PlayerError
| SourceError
| VideoViewError
| UnknownError;
class VideoError<TCode extends VideoErrorCode> extends Error {
readonly code: TCode;
readonly message: string;
readonly stack?: string;
}
class VideoComponentError extends VideoError<VideoViewError> {}
class VideoRuntimeError extends VideoError<
LibraryError | PlayerError | SourceError | UnknownError
> {}