ytdl-org/youtube-dl · error · ExtractorError

Video %s is not available

Error message

Video %s is not available

What it means

Raised by the Arte extractor when the player config JSON (videoJsonPlayer) contains no VSR (Video Source References) entry. If the API supplied custom_msg with type 'error', that message is used instead; otherwise the generic 'Video %s is not available' is raised with the VID. Marked expected=True.

Source

Thrown at youtube_dl/extractor/arte.py:69

    def _real_extract(self, url):
        mobj = re.match(self._VALID_URL, url)
        video_id = mobj.group('id')
        lang = mobj.group('lang') or mobj.group('lang_2')

        info = self._download_json(
            '%s/config/%s/%s' % (self._API_BASE, lang, video_id), video_id)
        player_info = info['videoJsonPlayer']

        vsr = try_get(player_info, lambda x: x['VSR'], dict)
        if not vsr:
            error = None
            if try_get(player_info, lambda x: x['custom_msg']['type']) == 'error':
                error = try_get(
                    player_info, lambda x: x['custom_msg']['msg'], compat_str)
            if not error:
                error = 'Video %s is not available' % player_info.get('VID') or video_id
            raise ExtractorError(error, expected=True)

        upload_date_str = player_info.get('shootingDate')
        if not upload_date_str:
            upload_date_str = (player_info.get('VRA') or player_info.get('VDA') or '').split(' ')[0]

        title = (player_info.get('VTI') or player_info['VID']).strip()
        subtitle = player_info.get('VSU', '').strip()
        if subtitle:
            title += ' - %s' % subtitle

        qfunc = qualities(['MQ', 'HQ', 'EQ', 'SQ'])

        LANGS = {
            'fr': 'F',
            'de': 'A',
            'en': 'E[ANG]',
            'es': 'E[ESP]',
            'it': 'E[ITA]',

View on GitHub (pinned to 956b8c5855)

Solutions

  1. If custom_msg was shown, follow its text (usually expiry or geo reason)
  2. Retry from a DE/FR IP for geo-restricted items
  3. Try the other language variant of the URL (arte.fr vs arte.de) which can have different availability
  4. For expired content, look for a rebroadcast with a fresh video id
Defensive patterns

Strategy: try-catch

Validate before calling

# Optional: probe the Arte config for VSR before full extraction
import requests
cfg = requests.get('https://api.arte.tv/api/player/v1/config/de/%s' % video_id).json()
player = cfg.get('videoJsonPlayer', {})
if not player.get('VSR'):
    reason = (player.get('custom_msg') or {}).get('msg', 'no VSR')
    skip(url, reason=reason)

Try / catch

try:
    ydl.extract_info(url)
except ExtractorError as e:
    msg = str(e)
    if 'not available' in msg:
        if is_geo_reason(msg):
            requeue_with_region(url, 'DE')  # or 'FR'
        else:
            mark_url_dead(url)  # expired arte+7 content

Prevention

When it happens

Trigger: GET <API_BASE>/config/<lang>/<video_id> returns videoJsonPlayer without VSR; geo-restricted arte content viewed from outside allowed regions; content past its streaming window; custom_msg type 'error' carrying the site's reason.

Common situations: Extracting arte+7 content after its 7-day expiry; watching French/German-locked items from other countries; lang parameter (de/fr) mismatch for a language-exclusive item.

Related errors


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