yt-dlp/yt-dlp · error · ExtractorError
Cannot find on-air {video_id} channel.
Error message
Cannot find on-air {video_id} channel. What it means
For AbemaTV 'now-on-air' URLs the extractor downloads the live channel list from api.abema.io/v1/channels (with division=1 for news-global) and linearly matches video_id against each channel's id to grab its HLS playback URL. If the loop completes with no match, this expected ExtractorError is raised: the channel slug in your URL is not currently broadcasting (or not present in the API's response).
Source
Thrown at yt_dlp/extractor/abematv.py:372
info['season_number'] = seri if seri < 100 else None
# some anime like Detective Conan (though not available in AbemaTV)
# has more than 1000 episodes (1026 as of 2021/11/15)
info['episode_number'] = epis if epis < 2000 else None
is_live, m3u8_url = False, None
availability = 'public'
if video_type == 'now-on-air':
is_live = True
channel_url = 'https://api.abema.io/v1/channels'
if video_id == 'news-global':
channel_url = update_url_query(channel_url, {'division': '1'})
onair_channels = self._download_json(channel_url, video_id)
for ch in onair_channels['channels']:
if video_id == ch['id']:
m3u8_url = ch['playback']['hls']
break
else:
raise ExtractorError(f'Cannot find on-air {video_id} channel.', expected=True)
elif video_type == 'episode':
api_response = self._download_json(
f'https://api.abema.io/v1/video/programs/{video_id}', video_id,
note='Checking playability',
headers=headers)
if not traverse_obj(api_response, ('label', 'free', {bool})):
# cannot acquire decryption key for these streams
self.report_warning('This is a premium-only stream')
availability = 'premium_only'
info.update(traverse_obj(api_response, {
'series': ('series', 'title'),
'season': ('season', 'name'),
'season_number': ('season', 'sequence'),
'episode_number': ('episode', 'number'),
}))
if not title:
title = traverse_obj(api_response, ('episode', 'title'))
if not description:View on GitHub (pinned to 81ecd58b13)
Solutions
- Pick a current live channel from https://abema.tv/now-on-air and use that fresh URL/slug
- Double-check the slug spelling against the site; news-global is the special-cased id for the news division
- If outside Japan, route through a JP VPN/proxy (or --proxy) — Abema geo-restricts its API responses
- Update yt-dlp in case the API contract changed, then retest with -v
Defensive patterns
Strategy: try-catch
Try / catch
from yt_dlp.utils import ExtractorError
try:
info = ydl.extract_info(url, download=True)
except ExtractorError as e:
if e.expected and 'Cannot find on-air' in str(e):
logger.info('channel off-air or geo-blocked; refresh the now-on-air slug: %s', url)
else:
raise Prevention
- Resolve live slugs dynamically from abema.tv/now-on-air instead of caching channel URLs
- Outside Japan, configure a JP proxy consistently for both page and API requests
- Treat expected=true extractor errors as 'skip and refresh channel list', not as bugs
When it happens
Trigger: A URL like https://abema.tv/now-on-air/SLUG where SLUG is not among onair_channels['channels'][*]['id'] — e.g. the channel went off-air and Abema rotated slugs, a typo in the slug, or the API returned a reduced channel set because of geoblocking (Abema is Japan-only).
Common situations: Watching a time-limited live channel that ended; copied stale URLs; accessing Abema from outside Japan without a JP exit node so the channels payload differs; scheduled channels that have not started.
Related errors
- {error}
- The channel is not currently live
- This video may be deleted or geo-restricted. You might want
- This video is restricted
- This video is not available from your location due to geo re
AI-assisted analysis of yt-dlp/yt-dlp@81ecd58b13 (2026-08-22).
Data as JSON: /api/errors/319825b331563c42.
Report an issue: GitHub.