ytdl-org/youtube-dl · error · ExtractorError

No API host found

Error message

No API host found

What it means

Raised by the GB News extractor when the Simplestream metadata endpoint (self._SSMP_URL, downloaded with fatal=False) returns JSON lacking response.api_hostname. Because the download is non-fatal, network failure also funnels here: json_data can be None and traverse_obj yields nothing.

Source

Thrown at youtube_dl/extractor/gbnews.py:94

            webpage, 'video data')

        video_data = extract_attributes(video_data)
        ss_id = video_data.get('data-id')
        if not ss_id:
            raise ExtractorError('Simplestream ID not found')

        json_data = self._download_json(
            self._SSMP_URL, display_id,
            note='Downloading Simplestream JSON metadata',
            errnote='Unable to download Simplestream JSON metadata',
            query={
                'id': ss_id,
                'env': video_data.get('data-env', 'production'),
            }, fatal=False)

        meta_url = traverse_obj(json_data, ('response', 'api_hostname'))
        if not meta_url:
            raise ExtractorError('No API host found')

        uvid = video_data['data-uvid']
        dtype = video_data.get('data-type')
        stream_data = self._download_json(
            '%s/api/%s/stream/%s' % (meta_url, 'show' if dtype == 'vod' else dtype, uvid),
            uvid,
            query={
                'key': video_data.get('data-key'),
                'platform': self._PLATFORM,
            },
            headers={
                'Token': video_data.get('data-token'),
                'Token-Expiry': video_data.get('data-expiry'),
                'Uvid': uvid,
            }, fatal=False)

        stream_url = traverse_obj(stream_data, (
            'response', 'stream', T(url_or_none)))

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Re-run with -v to see whether the SSMP JSON request actually failed (fatal=False hides it)
  2. Update youtube-dl/yt-dlp to pick up SSMP URL/host changes
  3. Manually curl the SSMP URL with the page's data-id and data-env to inspect the JSON returned
  4. If the video was removed, try a different GB News URL or the broadcaster's official app
Defensive patterns

Strategy: try-catch

Validate before calling

import requests
r = requests.get(SSMP_URL, params={'id': ss_id, 'env': env})
if not r.ok() or not r.json().get('response', {}).get('api_hostname'):
    print('SSMP metadata unavailable or missing api_hostname')

Type guard

def ssmp_meta_ok(json_data):
    return (
        isinstance(json_data, dict)
        and isinstance(json_data.get('response'), dict)
        and isinstance(json_data['response'].get('api_hostname'), str)
    )

Try / catch

try:
    info = ydl.extract_info(url)
except DownloadError as e:
    if 'No API host found' in str(e):
        retry_later_or_report(url)  # could be transient (fatal=False) or site change
    else:
        raise

Prevention

When it happens

Trigger: Querying the SSMP endpoint with the page's data-id/data-env returns an error payload (bad/expired ID, wrong env) instead of {response: {api_hostname: ...}}, or the request silently failed because fatal=False swallowed the network error.

Common situations: Expired or removed video IDs, Simplestream rotating API hostnames without updating the SSMP service, data-env other than 'production' pointing at a dead environment, or transient network failures masked by fatal=False.

Related errors


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