ytdl-org/youtube-dl · error · ExtractorError
Unable to extract moment id
Error message
Unable to extract moment id
What it means
Raised inside _extract_moment (younow.py) when a moment item from the YouNow moments API has a falsy 'momentId' field and the fatal flag is True. Moments are short clips; without a momentId there is nothing to construct a URL from, so extraction cannot proceed. Callers that pass fatal=False get None back instead of the exception.
Source
Thrown at youtube_dl/extractor/younow.py:85
'uploader_url': 'https://www.younow.com/%s' % username,
'creator': uploader,
'view_count': int_or_none(data.get('viewers')),
'like_count': int_or_none(data.get('likes')),
'formats': [{
'url': '%s/broadcast/videoPath/hls=1/broadcastId=%s/channelId=%s'
% (CDN_API_BASE, data['broadcastId'], data['userId']),
'ext': 'mp4',
'protocol': 'm3u8',
}],
}
def _extract_moment(item, fatal=True):
moment_id = item.get('momentId')
if not moment_id:
if not fatal:
return
raise ExtractorError('Unable to extract moment id')
moment_id = compat_str(moment_id)
title = item.get('text')
if not title:
title = 'YouNow %s' % (
item.get('momentType') or item.get('titleType') or 'moment')
uploader = try_get(item, lambda x: x['owner']['name'], compat_str)
uploader_id = try_get(item, lambda x: x['owner']['userId'])
uploader_url = 'https://www.younow.com/%s' % uploader if uploader else None
entry = {
'extractor_key': 'YouNowMoment',
'id': moment_id,
'title': title,
'view_count': int_or_none(item.get('views')),
'like_count': int_or_none(item.get('likes')),View on GitHub (pinned to 956b8c5855)
Solutions
- Inspect the failing item dict (log item.keys()) and confirm whether 'momentId' exists under a different key or nesting.
- If some items legitimately lack the id, call _extract_moment(item, fatal=False) so they are skipped instead of aborting the batch.
- Pre-filter the items list before extraction: keep only entries with a truthy 'momentId'.
- If the field was renamed by the API, update item.get('momentId') to the new key in younow.py.
Example fix
// before entries = [_extract_moment(item) for item in items] // after entries = [_extract_moment(item, fatal=False) for item in items] entries = [e for e in entries if e]
Defensive patterns
Strategy: validation
Validate before calling
def moment_items_valid(items) -> bool:
return all(item.get('momentId') for item in items) Type guard
def is_valid_moment(item: dict) -> bool:
return isinstance(item, dict) and bool(item.get('momentId')) Try / catch
try:
entry = _extract_moment(item)
except ExtractorError as e:
if 'Unable to extract moment id' in str(e):
continue # skip malformed/deleted moment in a batch
raise Prevention
- Filter items on a truthy 'momentId' before batch extraction.
- Use the fatal=False parameter offered by _extract_moment instead of hand-rolling catches.
When it happens
Trigger: Iterating channel moments where an entry in the API response lacks 'momentId' (deleted moments, placeholder entries, API schema drift) while calling _extract_moment with the default fatal=True.
Common situations: Channel scrape hit a moment deleted between listing and extraction; YouNow changed the field name (e.g. to 'momentId' vs an id nested object); processing raw API JSON that mixes non-moment entries into the items array.
Related errors
AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14).
Data as JSON: /api/errors/6006fa2f4176416f.
Report an issue: GitHub.