yt-dlp/yt-dlp · error · ExtractorError

Unable to extract video info

Error message

Unable to extract video info

What it means

Thrown by NaverIE._real_extract (yt_dlp/extractor/naver.py:203). The TVCAST API call GET /clips/<id>/play-info succeeded, but the response is missing clip.videoId (the real media id) or play.inKey (the playback access key); without both, the follow-up streams endpoint cannot even be requested.

Source

Thrown at yt_dlp/extractor/naver.py:203

            'comment_count': int,
            'duration': 69,
            'thumbnail': r're:^https?://.*\.jpg',
        },
        'params': {'format': 'HLS_144P'},
    }, {
        'url': 'http://tvcast.naver.com/v/81652',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        data = self._call_api(f'/clips/{video_id}/play-info', video_id)

        vid = traverse_obj(data, ('clip', 'videoId', {str}))
        in_key = traverse_obj(data, ('play', 'inKey', {str}))

        if not vid or not in_key:
            raise ExtractorError('Unable to extract video info')

        info = self._extract_video_info(video_id, vid, in_key)
        info.update(traverse_obj(data, ('clip', {
            'title': 'title',
            'description': 'description',
            'timestamp': ('firstExposureDatetime', {parse_iso8601}),
            'duration': ('playTime', {int_or_none}),
            'like_count': ('likeItCount', {int_or_none}),
            'view_count': ('playCount', {int_or_none}),
            'comment_count': ('commentCount', {int_or_none}),
            'thumbnail': ('thumbnailImageUrl', {url_or_none}),
            'uploader': 'channelName',
            'uploader_id': 'channelId',
            'uploader_url': ('channelUrl', {url_or_none}),
            'age_limit': ('adultVideo', {lambda x: 19 if x else None}),
        })))
        return info

View on GitHub (pinned to 81ecd58b13)

Solutions

  1. Open the clip URL in a browser (ideally from Korea) and confirm it still plays
  2. Retry with --proxy using a Korean exit node - many Naver clips are KR-only
  3. Pass cookies if the clip requires login
  4. Update yt-dlp to latest nightly
  5. Report with --verbose if the play-info JSON shape changed
Defensive patterns

Strategy: try-catch

Validate before calling

import json, urllib.request

def naver_clip_extractable(video_id) -> bool:
    api = f'https://tv.naver.com/api/clips/{video_id}/play-info'
    with urllib.request.urlopen(api) as r:
        data = json.load(r)
    return bool(data.get('clip', {}).get('videoId') and data.get('play', {}).get('inKey'))

Type guard

def play_info_complete(data: dict) -> bool:
    return bool(data.get('clip', {}).get('videoId')) and bool(data.get('play', {}).get('inKey'))

Try / catch

from yt_dlp.utils import ExtractorError
try:
    info = ydl.extract_info(url, download=False)
except ExtractorError as e:
    if 'Unable to extract video info' in str(e):
        # missing videoId/inKey: deleted, private, or region-locked clip
        mark_unavailable(url)

Prevention

When it happens

Trigger: _call_api('/clips/<video_id>/play-info') returns JSON where traverse_obj of ('clip','videoId') or ('play','inKey') comes back empty: clip deleted or privated, region-locked content (Naver frequently restricts to KR), or a changed API schema.

Common situations: Clip removed/made private; accessing NaverTV from outside Korea or from datacenter IPs; Naver API changes after site updates; clips that only play in the mobile app.

Related errors


AI-assisted analysis of yt-dlp/yt-dlp@81ecd58b13 (2026-08-22). Data as JSON: /api/errors/d2aa3cb0992641ad. Report an issue: GitHub.