ytdl-org/youtube-dl · error · ExtractorError

%s said: %s

Error message

%s said: %s

What it means

Raised by the Disney/ABC GO extractor when the entitlement API (api.entitlement.watchabc.go.com .../authorize.json) returns a non-empty errors list. Error code 1002 is first mapped to raise_geo_restricted; any remaining errors are joined into this ExtractorError. Marked expected=True.

Source

Thrown at youtube_dl/extractor/go.py:252

                        url, video_id, requestor_id, resource)
                    data.update({
                        'token': auth,
                        'token_type': 'ap',
                        'adobe_requestor_id': requestor_id,
                    })
                else:
                    self._initialize_geo_bypass({'countries': ['US']})
                entitlement = self._download_json(
                    'https://api.entitlement.watchabc.go.com/vp2/ws-secure/entitlement/2020/authorize.json',
                    video_id, data=urlencode_postdata(data))
                errors = entitlement.get('errors', {}).get('errors', [])
                if errors:
                    for error in errors:
                        if error.get('code') == 1002:
                            self.raise_geo_restricted(
                                error['message'], countries=['US'])
                    error_message = ', '.join([error['message'] for error in errors])
                    raise ExtractorError('%s said: %s' % (self.IE_NAME, error_message), expected=True)
                asset_url += '?' + entitlement['uplynkData']['sessionKey']
                formats.extend(self._extract_m3u8_formats(
                    asset_url, video_id, 'mp4', m3u8_id=format_id or 'hls', fatal=False))
            else:
                f = {
                    'format_id': format_id,
                    'url': asset_url,
                    'ext': ext,
                }
                if re.search(r'(?:/mp4/source/|_source\.mp4)', asset_url):
                    f.update({
                        'format_id': ('%s-' % format_id if format_id else '') + 'SOURCE',
                        'preference': 1,
                    })
                else:
                    mobj = re.search(r'/(\d+)x(\d+)/', asset_url)
                    if mobj:
                        height = int(mobj.group(2))

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Read the joined message: geo messages need a US exit; auth errors need fresh page tokens
  2. Update youtube-dl/yt-dlp for current go.com/Freeform endpoints
  3. Confirm the episode is still listed on the site
  4. If US-based and still failing, retry after clearing cookies so fresh tokens are fetched
Defensive patterns

Strategy: try-catch

Validate before calling

import requests
ent = requests.post('https://api.entitlement.watchabc.go.com/vp2/ws-secure/entitlement/2020/authorize.json', data=payload).json()
errs = ent.get('errors', {}).get('errors', [])
if errs:
    codes = [e.get('code') for e in errs]
    print('Entitlement errors:', codes, [e.get('message') for e in errs])

Type guard

def entitlement_ok(ent):
    return not ent.get('errors', {}).get('errors') and 'uplynkData' in ent

Try / catch

try:
    ydl.extract_info(url)
except DownloadError as e:
    msg = str(e)
    if 'said:' in msg and ('go.com' in msg.lower() or 'freeform' in msg.lower()):
        handle_entitlement_failure(url, msg)
    else:
        raise

Prevention

When it happens

Trigger: Authorizing playback of a go.com/freeform/abc video where the API returns errors other than (or after handling) code 1002 — e.g. auth/token errors, content no longer available, or non-geo entitlement failures.

Common situations: Outside-US access without geo bypass (though 1002 usually short-circuits to geo-restricted first), expired page tokens, removed episodes, or changes to the entitlement endpoint in older youtube-dl builds.

Related errors


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