ytdl-org/youtube-dl · error · ExtractorError

lynda returned error: %s

Error message

lynda returned error: %s

What it means

Raised by LyndaIE when the single-video API response contains a 'Status' key, which Lynda only includes when the request failed. The message embeds video['Message'], Lynda's own description of the failure (e.g. 'Video not found'). Marked expected=True because it maps a well-formed service error to a user-visible message.

Source

Thrown at youtube_dl/extractor/lynda.py:186

                    })
            self._sort_formats(formats)

            conviva = self._download_json(
                'https://www.lynda.com/ajax/player/conviva', video_id,
                'Downloading conviva JSON', query=query)

            return {
                'id': video_id,
                'title': conviva['VideoTitle'],
                'description': conviva.get('VideoDescription'),
                'release_year': int_or_none(conviva.get('ReleaseYear')),
                'duration': int_or_none(conviva.get('Duration')),
                'creator': conviva.get('Author'),
                'formats': formats,
            }

        if 'Status' in video:
            raise ExtractorError(
                'lynda returned error: %s' % video['Message'], expected=True)

        if video.get('HasAccess') is False:
            self._raise_unavailable(video_id)

        video_id = compat_str(video.get('ID') or video_id)
        duration = int_or_none(video.get('DurationInSeconds'))
        title = video['Title']

        formats = []

        fmts = video.get('Formats')
        if fmts:
            formats.extend([{
                'url': f['Url'],
                'ext': f.get('Extension'),
                'width': int_or_none(f.get('Width')),
                'height': int_or_none(f.get('Height')),

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Read the embedded Message text; it states Lynda's reason (most often that the video id does not exist).
  2. Confirm the video id by opening the lynda.com URL in a browser; if it 404s there, the id is dead.
  3. Log in with entitled credentials (--username/--password or --cookies) if the video requires a subscription.
  4. Update youtube-dl in case the video endpoint changed, then retry with -v to capture the raw response.
Defensive patterns

Strategy: try-catch

Type guard

def lynda_video_has_error(video_json):
    return isinstance(video_json, dict) and 'Status' in video_json

Try / catch

try:
    info = ydl.extract_info(url, download=False)
except ExtractorError as e:
    if 'lynda returned error' in str(e):
        msg = str(e).rsplit(':', 1)[1].strip()  # e.g. 'Video not found'
        log_skip(url, msg)  # treat as dead resource, continue batch
    else:
        raise

Prevention

When it happens

Trigger: GET of the lynda.com video REST endpoint returns JSON whose top-level object has a truthy/any 'Status' key; the very next line's HasAccess check is never reached because the raise happens first.

Common situations: Downloading a video id that was removed or unpublished; a course video whose id was scraped from a stale playlist page; an account without entitlement seeing Status-based refusals; API version changes making previously silent errors visible.

Related errors


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