ytdl-org/youtube-dl · error · ExtractorError

%s

Error message

%s

What it means

Raised from ShahidBaseIE._handle_error when an AWS API Gateway call to api2.shahid.net fails and the HTTP error body parses as JSON containing a 'faults' array. Each fault's 'userMessage' (cleaned of HTML) is joined into one message and re-raised as an expected ExtractorError. It converts opaque AWS gateway faults into readable, user-facing Shahid API errors.

Source

Thrown at youtube_dl/extractor/shahid.py:33

    parse_iso8601,
    str_or_none,
    urlencode_postdata,
)


class ShahidBaseIE(AWSIE):
    _AWS_PROXY_HOST = 'api2.shahid.net'
    _AWS_API_KEY = '2RRtuMHx95aNI1Kvtn2rChEuwsCogUd4samGPjLh'
    _VALID_URL_BASE = r'https?://shahid\.mbc\.net/[a-z]{2}/'

    def _handle_error(self, e):
        fail_data = self._parse_json(
            e.cause.read().decode('utf-8'), None, fatal=False)
        if fail_data:
            faults = fail_data.get('faults', [])
            faults_message = ', '.join([clean_html(fault['userMessage']) for fault in faults if fault.get('userMessage')])
            if faults_message:
                raise ExtractorError(faults_message, expected=True)

    def _call_api(self, path, video_id, request=None):
        query = {}
        if request:
            query['request'] = json.dumps(request)
        try:
            return self._aws_execute_api({
                'uri': '/proxy/v2/' + path,
                'access_key': 'AKIAI6X4TYCIXM2B7MUQ',
                'secret_key': '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',
            }, video_id, query)
        except ExtractorError as e:
            if isinstance(e.cause, compat_HTTPError):
                self._handle_error(e)
            raise


class ShahidIE(ShahidBaseIE):

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Read the userMessage text: it names the real fault (session, entitlement, geo, or auth).
  2. If it is a session/device fault, re-run with a clean cache so the extractor regenerates its session (--no-cache-dir / delete ~/.cache/youtube-dl).
  3. If the fault is entitlement/DRM, the asset requires a Shahid subscription and cannot be downloaded anonymously.
  4. If every request faults with an auth/signature message, the extractor's embedded AWS credentials are stale - update to the latest youtube-dl/yt-dlp where new keys are shipped.
  5. If geo-blocked, use an appropriate VPN region or choose another source.
Defensive patterns

Strategy: try-catch

Try / catch

try:
    result = shahid_call(path, video_id)
except ExtractorError as e:
    if e.expected and 'session' in str(e).lower():
        clear_cache(); retry_once()
    else:
        log_fault_message(str(e))

Prevention

When it happens

Trigger: Any _call_api invocation (e.g. playout/new/url/<id>, getuser or product endpoints) where _aws_execute_api raises ExtractorError whose cause is an HTTPError whose body has {'faults': [{'userMessage': ...}]}. Common fault causes: expired/invalid device session, DRM-restricted asset requiring subscription, geo restriction, or an expired API key/signature.

Common situations: Expired Shahid session token (the API demands a fresh deviceId/sessionId); trying to play premium/DRM content on a free account; the hard-coded AWS access key/secret in the extractor being rotated by MBC so every call is rejected with a signature fault; region blocks outside the MBC footprint.

Related errors


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