ytdl-org/youtube-dl · error · ExtractorError

response['body']['message']

Error message

response['body']['message']

What it means

Raised by the Hotstar extractor's _call_api when the API response's statusCode is not 'OK'; the message comes from response['body']['message']. Marked expected=True. Note: if body or message is missing on a non-OK response this line KeyErrors, but the normal path surfaces Hotstar's own message (geo, entitlement, not-found).

Source

Thrown at youtube_dl/extractor/hotstar.py:49

        exp = st + 6000
        auth = 'st=%d~exp=%d~acl=/*' % (st, exp)
        auth += '~hmac=' + hmac.new(self._AKAMAI_ENCRYPTION_KEY, auth.encode(), hashlib.sha256).hexdigest()
        h = {'hotstarauth': auth}
        h.update(headers)
        return self._download_json(
            'https://api.hotstar.com/' + path,
            video_id, headers=h, query=query, data=data)

    def _call_api(self, path, video_id, query_name='contentId'):
        response = self._call_api_impl(path, video_id, {
            'x-country-code': 'IN',
            'x-platform-code': 'JIO',
        }, {
            query_name: video_id,
            'tas': 10000,
        })
        if response['statusCode'] != 'OK':
            raise ExtractorError(
                response['body']['message'], expected=True)
        return response['body']['results']

    def _call_api_v2(self, path, video_id, headers, query=None, data=None):
        h = {'X-Request-Id': compat_str(uuid.uuid4())}
        h.update(headers)
        try:
            return self._call_api_impl(
                path, video_id, h, query, data)
        except ExtractorError as e:
            if isinstance(e.cause, compat_HTTPError):
                if e.cause.code == 402:
                    self.raise_login_required()
                message = self._parse_json(e.cause.read().decode(), video_id)['message']
                if message in ('Content not available in region', 'Country is not supported'):
                    raise self.raise_geo_restricted(message)
                raise ExtractorError(message)
            raise e

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Read the body message with -v: it distinguishes geo vs entitlement vs not-found
  2. For premium content, pass credentials/cookies of an entitled account
  3. Update to yt-dlp — Hotstar's API and headers changed repeatedly
  4. Verify the content still plays on hotstar.com in a browser
Defensive patterns

Strategy: try-catch

Validate before calling

import requests
resp = requests.get(f'https://api.hotstar.com/{path}', params={'contentId': vid, 'tas': 10000}, headers={'x-country-code': 'IN', 'x-platform-code': 'JIO'}).json()
if resp.get('statusCode') != 'OK':
    print('Hotstar refusal:', resp.get('body', {}).get('message'))

Type guard

def hotstar_ok(response):
    return (
        isinstance(response, dict)
        and response.get('statusCode') == 'OK'
        and isinstance(response.get('body'), dict)
        and 'results' in response['body']
    )

Try / catch

try:
    ydl.extract_info(url)
except DownloadError as e:
    if 'Hotstar' in str(e) or 'hotstar' in str(e):
        classify_and_log(url, str(e))  # geo vs entitlement vs removed
    else:
        raise

Prevention

When it happens

Trigger: Calling api.hotstar.com with x-country-code: IN and x-platform-code: JIO for content that is not available in India, is premium-only, or has been removed — statusCode comes back non-OK with an error body.

Common situations: Premium Hotstar content without subscription login, region-locked content (headers force IN region), removed matches/episodes, or old builds predating Hotstar's API changes (now JioHotstar).

Related errors


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