November 10, 2026 · 4 min read
Fix youtube-transcript-api NoTranscriptFound
In short
NoTranscriptFound means the video has captions, just not under the exact language code you asked for, often de vs de-DE or a missing en track. List the tracks, match a regional code, or translate one.
NoTranscriptFound is the most misleading error in youtube-transcript-api: the video usually does have a transcript. fetch() only accepts exact language codes, and it asks for English by default, so a German video with a de-DE track fails when you ask for "de", and any video without an English track fails when you ask for nothing.
What the error says
Read the whole message: it lists the codes you asked for, then every track the video actually has. Here the video has German as de-DE, so "de" fails:
YouTubeTranscriptApi().fetch("dQw4w9WgXcQ", languages=["de"])
# NoTranscriptFound: No transcripts were found for any of the
# requested language codes: ['de']
#
# (MANUALLY CREATED)
# - en ("English")[TRANSLATABLE]
# - de-DE ("German (Germany)")[TRANSLATABLE]
# - pt-BR ("Portuguese (Brazil)")[TRANSLATABLE]
# (GENERATED)
# - en ("English (auto-generated)")[TRANSLATABLE]Fix 1: match regional codes
List the tracks and pick by the part before the hyphen, so de matches de-DE and de-AT. Prefer a manually created track over the auto-generated one.
from youtube_transcript_api import YouTubeTranscriptApi
def fetch_language(video_id, lang):
tracks = list(YouTubeTranscriptApi().list(video_id))
same = [t for t in tracks if t.language_code.split("-")[0] == lang]
if not same:
return None
best = next((t for t in same if not t.is_generated), same[0])
return best.fetch().to_raw_data()Fix 2: take whatever language the video has
For summaries and search you often want the spoken language, whatever it is. The auto-generated track is always in the spoken language.
tracks = list(YouTubeTranscriptApi().list(video_id)) spoken = next((t for t in tracks if t.is_generated), tracks[0]) print(spoken.language_code, spoken.fetch().to_raw_data()[:3])
Fix 3: translate an existing track
Tracks marked [TRANSLATABLE] can be machine-translated by YouTube into any listed language.
tracks = YouTubeTranscriptApi().list(video_id)
english = tracks.find_transcript(["de-DE"]).translate("en").fetch()The API does the matching for you
With the TranscriptYT API, language=de picks de-DE or any other German track, a missing language is translated from the original, and no language returns English or the spoken language. Call /v1/languages to see every track first. If the video has no captions at all, it is transcribed with AI instead of failing.
curl "https://transcript-yt.com/v1/transcript?url=dQw4w9WgXcQ&language=de" \ -H "Authorization: Bearer $TRANSCRIPTYT_KEY"
Common questions
Why do I get NoTranscriptFound when the video has captions?
The language codes must match exactly. A track published as de-DE, pt-BR, or es-419 is not found when you ask for de, pt, or es, and fetch() asks for ["en"] by default, so non-English videos fail unless you pass their language.
How do I see which transcripts a video has?
Call YouTubeTranscriptApi().list(video_id) and print each track's language_code and is_generated. The NoTranscriptFound message also lists them.
How do I get a transcript in any language that exists?
List the tracks and fetch the first one, or pass several codes in priority order, for example languages=["en", "en-US", "en-GB"].
Can I get an English transcript of a video that has no English captions?
Yes, if its track is translatable: transcript_list.find_transcript(["de-DE"]).translate("en").fetch(). The TranscriptYT API does this automatically when you pass language=en.
Is NoTranscriptFound the same as TranscriptsDisabled?
No. NoTranscriptFound means captions exist in other languages. TranscriptsDisabled means the video has no captions at all, which needs AI transcription of the audio.