0
# Exception Handling
1
2
Comprehensive exception hierarchy for handling various error conditions including video availability, network issues, extraction failures, and other operational errors in pytube.
3
4
## Capabilities
5
6
### Base Exception
7
8
Root exception class for all pytube-specific errors.
9
10
```python { .api }
11
class PytubeError(Exception):
12
"""
13
Base exception class for all pytube errors.
14
15
All other pytube exceptions inherit from this base class,
16
allowing for comprehensive error handling.
17
"""
18
```
19
20
### Network and Retry Exceptions
21
22
Exceptions related to network operations and request failures.
23
24
```python { .api }
25
class MaxRetriesExceeded(PytubeError):
26
"""
27
Exception raised when maximum retry attempts are exceeded.
28
29
Occurs during download operations when network requests
30
fail repeatedly beyond the configured retry limit.
31
"""
32
```
33
34
### HTML Parsing and Data Extraction Exceptions
35
36
Exceptions related to parsing YouTube pages and extracting video data.
37
38
```python { .api }
39
class HTMLParseError(PytubeError):
40
"""
41
Exception raised when HTML parsing fails.
42
43
Occurs when pytube cannot parse YouTube page content,
44
often due to page structure changes or malformed HTML.
45
"""
46
47
class ExtractError(PytubeError):
48
"""
49
Exception raised when data extraction fails.
50
51
General exception for failures in extracting video information,
52
stream data, or metadata from YouTube responses.
53
"""
54
55
class RegexMatchError(ExtractError):
56
def __init__(self, caller: str, pattern: Union[str, Pattern]):
57
"""
58
Exception raised when regular expression matching fails.
59
60
Args:
61
caller (str): The function or method where the regex failed
62
pattern (str or Pattern): The regex pattern that failed to match
63
"""
64
```
65
66
### Video Availability Exceptions
67
68
Base class and specific exceptions for various video availability issues.
69
70
```python { .api }
71
class VideoUnavailable(PytubeError):
72
def __init__(self, video_id: str):
73
"""
74
Base exception for video unavailability issues.
75
76
Args:
77
video_id (str): The YouTube video ID that is unavailable
78
"""
79
80
class AgeRestrictedError(VideoUnavailable):
81
def __init__(self, video_id: str):
82
"""
83
Exception raised when video is age-restricted.
84
85
Occurs when attempting to access age-restricted content
86
without proper authentication or when content has
87
tier 3 age restrictions that cannot be bypassed.
88
89
Args:
90
video_id (str): The age-restricted video ID
91
"""
92
93
class LiveStreamError(VideoUnavailable):
94
def __init__(self, video_id: str):
95
"""
96
Exception raised when attempting to download live streams.
97
98
Live streams cannot be downloaded as they are ongoing
99
broadcasts without fixed content.
100
101
Args:
102
video_id (str): The live stream video ID
103
"""
104
105
class VideoPrivate(VideoUnavailable):
106
def __init__(self, video_id: str):
107
"""
108
Exception raised when video is private.
109
110
Occurs when attempting to access private videos that
111
require specific permissions or are only visible to
112
the uploader.
113
114
Args:
115
video_id (str): The private video ID
116
"""
117
118
class RecordingUnavailable(VideoUnavailable):
119
def __init__(self, video_id: str):
120
"""
121
Exception raised when live stream recording is unavailable.
122
123
Occurs when a live stream has ended but the recording
124
is not yet available or has been disabled.
125
126
Args:
127
video_id (str): The unavailable recording video ID
128
"""
129
130
class MembersOnly(VideoUnavailable):
131
def __init__(self, video_id: str):
132
"""
133
Exception raised when video is members-only content.
134
135
Occurs when attempting to access content restricted
136
to channel members without proper membership status.
137
138
Args:
139
video_id (str): The members-only video ID
140
"""
141
142
class VideoRegionBlocked(VideoUnavailable):
143
def __init__(self, video_id: str):
144
"""
145
Exception raised when video is blocked in the user's region.
146
147
Occurs when content is geo-restricted and not available
148
in the user's geographic location.
149
150
Args:
151
video_id (str): The region-blocked video ID
152
"""
153
```
154
155
## Usage Examples
156
157
### Basic Exception Handling
158
159
```python
160
from pytube import YouTube
161
from pytube.exceptions import VideoUnavailable, AgeRestrictedError, PytubeError
162
163
def safe_download(video_url):
164
"""Download video with comprehensive error handling."""
165
try:
166
yt = YouTube(video_url)
167
stream = yt.streams.get_highest_resolution()
168
169
if stream:
170
file_path = stream.download()
171
print(f"Successfully downloaded: {file_path}")
172
return file_path
173
else:
174
print("No suitable stream found")
175
return None
176
177
except VideoUnavailable as e:
178
print(f"Video unavailable: {e}")
179
return None
180
except AgeRestrictedError as e:
181
print(f"Age-restricted content: {e}")
182
return None
183
except PytubeError as e:
184
print(f"Pytube error: {e}")
185
return None
186
except Exception as e:
187
print(f"Unexpected error: {e}")
188
return None
189
190
# Usage
191
result = safe_download('https://www.youtube.com/watch?v=VIDEO_ID')
192
```
193
194
### Specific Exception Handling
195
196
```python
197
from pytube import YouTube
198
from pytube.exceptions import (
199
VideoPrivate, MembersOnly, LiveStreamError,
200
RecordingUnavailable, VideoRegionBlocked
201
)
202
203
def handle_specific_errors(video_url):
204
"""Handle specific video availability issues."""
205
try:
206
yt = YouTube(video_url)
207
return yt.streams.get_highest_resolution()
208
209
except VideoPrivate:
210
print("This video is private and cannot be accessed")
211
return None
212
213
except MembersOnly:
214
print("This video is for channel members only")
215
print("Consider becoming a channel member to access this content")
216
return None
217
218
except LiveStreamError:
219
print("Cannot download live streams - wait for the recording")
220
return None
221
222
except RecordingUnavailable:
223
print("Live stream recording not yet available")
224
return None
225
226
except VideoRegionBlocked:
227
print("Video is blocked in your region")
228
print("Consider using a VPN or proxy")
229
return None
230
231
# Usage
232
stream = handle_specific_errors('https://www.youtube.com/watch?v=VIDEO_ID')
233
```
234
235
### Retry Logic with Exception Handling
236
237
```python
238
from pytube import YouTube
239
from pytube.exceptions import MaxRetriesExceeded, ExtractError, HTMLParseError
240
import time
241
import random
242
243
def download_with_retry(video_url, max_attempts=3):
244
"""Download with custom retry logic."""
245
246
for attempt in range(max_attempts):
247
try:
248
print(f"Attempt {attempt + 1}/{max_attempts}")
249
250
yt = YouTube(video_url)
251
stream = yt.streams.get_highest_resolution()
252
253
if stream:
254
file_path = stream.download()
255
print(f"Download successful: {file_path}")
256
return file_path
257
258
except MaxRetriesExceeded:
259
print(f"Max retries exceeded on attempt {attempt + 1}")
260
if attempt < max_attempts - 1:
261
wait_time = random.uniform(1, 3) * (attempt + 1)
262
print(f"Waiting {wait_time:.1f} seconds before retry...")
263
time.sleep(wait_time)
264
265
except (ExtractError, HTMLParseError) as e:
266
print(f"Extraction/parsing error on attempt {attempt + 1}: {e}")
267
if attempt < max_attempts - 1:
268
print("Retrying with fresh YouTube object...")
269
time.sleep(2)
270
271
except Exception as e:
272
print(f"Unexpected error: {e}")
273
break
274
275
print("All attempts failed")
276
return None
277
278
# Usage
279
result = download_with_retry('https://www.youtube.com/watch?v=VIDEO_ID')
280
```
281
282
### Bulk Operations with Error Logging
283
284
```python
285
from pytube import Playlist
286
from pytube.exceptions import PytubeError, VideoUnavailable
287
import logging
288
from datetime import datetime
289
290
# Configure logging
291
logging.basicConfig(
292
level=logging.INFO,
293
format='%(asctime)s - %(levelname)s - %(message)s',
294
handlers=[
295
logging.FileHandler('pytube_errors.log'),
296
logging.StreamHandler()
297
]
298
)
299
300
def download_playlist_with_error_logging(playlist_url):
301
"""Download playlist with comprehensive error logging."""
302
303
try:
304
playlist = Playlist(playlist_url)
305
logging.info(f"Starting download of playlist: {playlist.title}")
306
logging.info(f"Total videos: {playlist.length}")
307
308
successful = []
309
failed = []
310
311
for i, video in enumerate(playlist.videos, 1):
312
try:
313
logging.info(f"Processing video {i}/{playlist.length}: {video.title}")
314
315
stream = video.streams.get_highest_resolution()
316
if stream:
317
file_path = stream.download()
318
successful.append({
319
'title': video.title,
320
'url': video.watch_url,
321
'file_path': file_path
322
})
323
logging.info(f"Successfully downloaded: {video.title}")
324
else:
325
raise PytubeError("No suitable stream found")
326
327
except VideoUnavailable as e:
328
error_info = {
329
'title': getattr(video, 'title', 'Unknown'),
330
'url': getattr(video, 'watch_url', 'Unknown'),
331
'error': str(e),
332
'error_type': type(e).__name__
333
}
334
failed.append(error_info)
335
logging.warning(f"Video unavailable: {error_info['title']} - {e}")
336
337
except PytubeError as e:
338
error_info = {
339
'title': getattr(video, 'title', 'Unknown'),
340
'url': getattr(video, 'watch_url', 'Unknown'),
341
'error': str(e),
342
'error_type': type(e).__name__
343
}
344
failed.append(error_info)
345
logging.error(f"Pytube error for {error_info['title']}: {e}")
346
347
except Exception as e:
348
error_info = {
349
'title': getattr(video, 'title', 'Unknown'),
350
'url': getattr(video, 'watch_url', 'Unknown'),
351
'error': str(e),
352
'error_type': type(e).__name__
353
}
354
failed.append(error_info)
355
logging.error(f"Unexpected error for {error_info['title']}: {e}")
356
357
# Summary logging
358
logging.info(f"Download completed - Success: {len(successful)}, Failed: {len(failed)}")
359
360
return {
361
'successful': successful,
362
'failed': failed,
363
'playlist_title': playlist.title
364
}
365
366
except Exception as e:
367
logging.error(f"Failed to process playlist {playlist_url}: {e}")
368
return None
369
370
# Usage
371
results = download_playlist_with_error_logging(
372
'https://www.youtube.com/playlist?list=PLAYLIST_ID'
373
)
374
375
if results:
376
print(f"Playlist: {results['playlist_title']}")
377
print(f"Successful downloads: {len(results['successful'])}")
378
print(f"Failed downloads: {len(results['failed'])}")
379
380
if results['failed']:
381
print("\nFailed downloads:")
382
for failure in results['failed']:
383
print(f"- {failure['title']}: {failure['error_type']}")
384
```
385
386
### Age-Restricted Content Handling
387
388
```python
389
from pytube import YouTube
390
from pytube.exceptions import AgeRestrictedError
391
392
def handle_age_restricted_content(video_url):
393
"""Handle age-restricted content with OAuth fallback."""
394
395
# First attempt without OAuth
396
try:
397
yt = YouTube(video_url)
398
yt.check_availability() # This will raise AgeRestrictedError if needed
399
400
stream = yt.streams.get_highest_resolution()
401
return stream.download()
402
403
except AgeRestrictedError:
404
print("Video is age-restricted, attempting OAuth authentication...")
405
406
try:
407
# Retry with OAuth
408
yt_oauth = YouTube(
409
video_url,
410
use_oauth=True,
411
allow_oauth_cache=True
412
)
413
414
stream = yt_oauth.streams.get_highest_resolution()
415
if stream:
416
return stream.download()
417
else:
418
print("No suitable stream found even with OAuth")
419
return None
420
421
except AgeRestrictedError:
422
print("Content has tier 3 age restrictions and cannot be accessed")
423
return None
424
425
except Exception as e:
426
print(f"OAuth authentication failed: {e}")
427
return None
428
429
# Usage
430
result = handle_age_restricted_content('https://www.youtube.com/watch?v=AGE_RESTRICTED_VIDEO')
431
```
432
433
### Custom Exception Context Manager
434
435
```python
436
from pytube import YouTube
437
from pytube.exceptions import PytubeError
438
from contextlib import contextmanager
439
440
@contextmanager
441
def pytube_error_context(operation_description="pytube operation"):
442
"""Context manager for pytube operations with standardized error handling."""
443
444
try:
445
yield
446
447
except VideoUnavailable as e:
448
print(f"Video unavailable during {operation_description}: {e}")
449
raise
450
451
except AgeRestrictedError as e:
452
print(f"Age-restricted content encountered during {operation_description}: {e}")
453
raise
454
455
except MaxRetriesExceeded as e:
456
print(f"Network issues during {operation_description}: {e}")
457
raise
458
459
except (ExtractError, HTMLParseError) as e:
460
print(f"Data extraction failed during {operation_description}: {e}")
461
raise
462
463
except PytubeError as e:
464
print(f"Pytube error during {operation_description}: {e}")
465
raise
466
467
except Exception as e:
468
print(f"Unexpected error during {operation_description}: {e}")
469
raise
470
471
# Usage
472
def safe_video_info(video_url):
473
with pytube_error_context("video info extraction"):
474
yt = YouTube(video_url)
475
return {
476
'title': yt.title,
477
'author': yt.author,
478
'length': yt.length,
479
'views': yt.views
480
}
481
482
# Usage
483
try:
484
info = safe_video_info('https://www.youtube.com/watch?v=VIDEO_ID')
485
print(f"Video info: {info}")
486
except PytubeError:
487
print("Failed to get video info due to pytube error")
488
except Exception:
489
print("Failed to get video info due to unexpected error")
490
```
491
492
## Types
493
494
```python { .api }
495
from typing import Union
496
import re
497
498
# Type for regex patterns
499
Pattern = Union[str, re.Pattern]
500
501
# Exception hierarchy summary for type checking
502
VideoAvailabilityError = Union[
503
VideoUnavailable,
504
AgeRestrictedError,
505
LiveStreamError,
506
VideoPrivate,
507
RecordingUnavailable,
508
MembersOnly,
509
VideoRegionBlocked
510
]
511
512
ExtractionError = Union[
513
HTMLParseError,
514
ExtractError,
515
RegexMatchError
516
]
517
518
NetworkError = Union[
519
MaxRetriesExceeded
520
]
521
```