ytdl-org/youtube-dl · error · ExtractorError

%s said: %s

Error message

%s said: %s

What it means

RadioCanadaBaseIE._extract_info calls validation/v2/ and, if the response contains no 'url', raises ExtractorError('%s said: %s' % (IE_NAME, error), expected=True) using v_data['message'] — after first checking for two known French messages (geo-restriction -> raise_geo_restricted, premium-only -> raise_login_required). So this branch is the generic validation failure: the API explicitly refused to provide a stream URL for a reason other than geo or premium.

Source

Thrown at youtube_dl/extractor/radiocanada.py:118

        if get_meta('protectionType'):
            self.report_warning('This video is probably DRM protected.')

        query = {
            'connectionType': 'hd',
            'deviceType': 'ipad',
            'multibitrate': 'true',
        }
        if self._claims:
            query['claims'] = self._claims
        v_data = self._call_api('validation/v2/', video_id, app_code, query)
        v_url = v_data.get('url')
        if not v_url:
            error = v_data['message']
            if error == "Le contenu sélectionné n'est pas disponible dans votre pays":
                raise self.raise_geo_restricted(error, self._GEO_COUNTRIES)
            if error == 'Le contenu sélectionné est disponible seulement en premium':
                self.raise_login_required(error)
            raise ExtractorError(
                '%s said: %s' % (self.IE_NAME, error), expected=True)
        formats = self._extract_m3u8_formats(v_url, video_id, 'mp4')
        self._sort_formats(formats)

        subtitles = {}
        closed_caption_url = get_meta('closedCaption') or get_meta('closedCaptionHTML5')
        if closed_caption_url:
            subtitles['fr'] = [{
                'url': closed_caption_url,
                'ext': determine_ext(closed_caption_url, 'vtt'),
            }]

        return {
            'id': video_id,
            'title': get_meta('Title') or get_meta('AV-nomEmission'),
            'description': get_meta('Description') or get_meta('ShortDescription'),
            'thumbnail': get_meta('imageHR') or get_meta('imageMR') or get_meta('imageBR'),
            'duration': int_or_none(get_meta('length')),

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Read the French message in the error text — it states the actual refusal reason from the API.
  2. Confirm the content is still available on the Radio-Canada/Tou.tv site in a browser.
  3. Update youtube-dl so newly worded geo/premium messages are recognized and routed to the proper handling.
  4. If it is availability-window related, there is no client fix — the content is gone server-side.
Defensive patterns

Strategy: try-catch

Try / catch

try:
    info = ydl.extract_info(url)
except ExtractorError as e:
    if 'said:' in str(e):
        read_french_message(e)  # names the real refusal reason

Prevention

When it happens

Trigger: validation/v2/ returns a dict without 'url' and with a message that is neither 'Le contenu sélectionné n'est pas disponible dans votre pays' nor '... seulement en premium' — e.g. expired content, removed media, or new refusal messages; note KeyError-style failure is avoided only because message is read via v_data['message'], which must exist.

Common situations: Expired news clips or live streams past their availability window; messages reworded by Radio-Canada so the geo/premium string matches fail and fall through to the generic error; deleted episodes on Tou.tv.

Related errors


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