yt-dlp/yt-dlp · error · ExtractorError
Invalid username/password
Error message
Invalid username/password
What it means
Raised by GameDevTVDLCourseIE._perform_login. The extractor POSTs email/password as JSON to https://api.gamedev.tv/api/students/login; an HTTP 401 response is translated to this expected 'Invalid username/password' error. On success, response['token_type'] + response['access_token'] become the Authorization header for all course API calls; without a login, _real_initialize raises login-required (content needs purchase).
Source
Thrown at yt_dlp/extractor/gamedevtv.py:74
'alt_title': '1_CC_MVX MagicaVoxel Community Course Introduction.mp4',
'thumbnail': 'https://vz-23691c65-6fa.b-cdn.net/df04f4d8-68a4-4756-a71b-9ca9446c3a01/thumbnail.jpg',
},
}]
_API_HEADERS = {}
def _perform_login(self, username, password):
try:
response = self._download_json(
'https://api.gamedev.tv/api/students/login', None, 'Logging in',
headers={'Content-Type': 'application/json'},
data=json.dumps({
'email': username,
'password': password,
'cart_items': [],
}).encode())
except ExtractorError as e:
if isinstance(e.cause, HTTPError) and e.cause.status == 401:
raise ExtractorError('Invalid username/password', expected=True)
raise
self._API_HEADERS['Authorization'] = f'{response["token_type"]} {response["access_token"]}'
def _real_initialize(self):
if not self._API_HEADERS.get('Authorization'):
self.raise_login_required(
'This content is only available with purchase', method='password')
def _entries(self, data, course_id, course_info, selected_lecture):
for section in traverse_obj(data, ('sections', ..., {dict})):
section_info = traverse_obj(section, {
'season_id': ('id', {str_or_none}),
'season': ('title', {str}),
'season_number': ('order', {int_or_none}),
})
for lecture in traverse_obj(section, ('lectures', lambda _, v: url_or_none(v['video']['playListUrl']))):
if selected_lecture and str(lecture.get('id')) != selected_lecture:View on GitHub (pinned to 81ecd58b13)
Solutions
- Confirm the email/password by logging in at gamedev.tv in a browser
- Re-run with the corrected --username/--password (or updated .netrc)
- If credentials are right but courses fail, check the account actually owns the course
- Update yt-dlp if the login endpoint moved
Example fix
# before yt-dlp --username me@mail.com --password 'old' 'https://www.gamedev.tv/courses/x' # after: corrected credentials yt-dlp --username me@mail.com --password 'new' 'https://www.gamedev.tv/courses/x'
Defensive patterns
Strategy: try-catch
Type guard
# If you call api.gamedev.tv yourself, guard the login response first
def token_of(response: dict) -> str | None:
if not isinstance(response, dict):
return None
tok, typ = response.get('access_token'), response.get('token_type')
return f'{typ} {tok}' if tok and typ else None Try / catch
from yt_dlp import YoutubeDL
from yt_dlp.utils import DownloadError
try:
with YoutubeDL({'username': USER, 'password': PASS}) as ydl:
ydl.download([course_url])
except DownloadError as e:
if 'Invalid username/password' in str(e):
fail_fast('fix credentials in .netrc / CLI arguments') # do NOT retry-loop a 401
else:
raise Prevention
- Confirm the login works at gamedev.tv before using it in scripts
- Never retry-loop a 401 - fix the credentials instead of hammering the endpoint
- Keep .netrc permissions tight and update it on every password rotation
When it happens
Trigger: Wrong email or password supplied to --username/--password; .netrc with stale entries; account that exists on the site but has no active course purchase (still logs in, fails later); API base URL changed by the site so the login endpoint 401s.
Common situations: Credential typos in automation; password rotations not reflected in .netrc; confusion between gamedev.tv site login and the api.gamedev.tv student login.
Related errors
- Login failed: Invalid id or password
- Wrong username and/or password.
- Unable to login: {error}
- ', '.join(auth['messages'])
- Login failed
AI-assisted analysis of yt-dlp/yt-dlp@81ecd58b13 (2026-08-22).
Data as JSON: /api/errors/e6050e40fbd160c4.
Report an issue: GitHub.