ytdl-org/youtube-dl · warning · ExtractorError

not a video

Error message

not a video

What it means

Raised by the Flickr extractor when the photo's media type in the API response is anything other than 'video'. Flickr hosts both photos and videos under the same URL scheme, and only video entries yield formats/duration; a plain photo falls through to this expected error. It is a clean, expected classification error, not a failure.

Source

Thrown at youtube_dl/extractor/flickr.py:116

            uploader_url = 'https://www.flickr.com/photos/%s/' % uploader_path if uploader_path else None

            return {
                'id': video_id,
                'title': video_info['title']['_content'],
                'description': video_info.get('description', {}).get('_content'),
                'formats': formats,
                'timestamp': int_or_none(video_info.get('dateuploaded')),
                'duration': int_or_none(video_info.get('video', {}).get('duration')),
                'uploader_id': uploader_id,
                'uploader': owner.get('realname'),
                'uploader_url': uploader_url,
                'comment_count': int_or_none(video_info.get('comments', {}).get('_content')),
                'view_count': int_or_none(video_info.get('views')),
                'tags': [tag.get('_content') for tag in video_info.get('tags', {}).get('tag', [])],
                'license': self._LICENSES.get(video_info.get('license')),
            }
        else:
            raise ExtractorError('not a video', expected=True)

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Inspect the URL's page in a browser: if it shows a still photo, this error is correct behavior
  2. Find the actual video item in the album and pass its individual /photos/<user>/<id> URL
  3. For still images, use an image downloader instead of a video extractor
  4. In batch pipelines, pre-filter items with flickr.photos.getInfo (media == 'video') before invoking the extractor

Example fix

# before
youtube_dl 'https://www.flickr.com/photos/user/11111111111'  # a photo
# ERROR: not a video

# after
youtube_dl 'https://www.flickr.com/photos/user/22222222222'  # the video item
Defensive patterns

Strategy: validation

Validate before calling

# Pre-filter to video media only
info = flickr_api_call('photos.getInfo', photo_id=pid)
if info['photo']['media'] != 'video':
    continue  # skip photos, avoid the extractor entirely

Type guard

def is_flickr_video(info: dict) -> bool:
    return (
        isinstance(info, dict)
        and isinstance(info.get('photo'), dict)
        and info['photo'].get('media') == 'video'
    )

Try / catch

try:
    ydl.extract_info(url)
except ExtractorError as e:
    if str(e) == 'not a video':
        continue  # expected for photos; skip silently

Prevention

When it happens

Trigger: _call_api('photos.getInfo') returns video_info['media'] != 'video', so the else branch raises 'not a video' with expected=True. Produced by passing a photo (still image) URL to a video downloader, e.g. an album page link or a single image in a photoset.

Common situations: Feeding Flickr album/set URLs to youtube-dl; batch jobs that enumerate all photo ids in an account and hit the non-video majority; users assuming every Flickr URL is downloadable video.

Related errors


AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14). Data as JSON: /api/errors/301ee90a68d23c96. Report an issue: GitHub.