Back to blog

Python · youtube-transcript-api · Troubleshooting

'YouTubeTranscriptApi' Has No Attribute 'get_transcript': Cause and Fix

youtube-transcript-api 1.2.0 removed get_transcript, get_transcripts and list_transcripts. The two-line fix, the errors that come right after it, and what to do when the old call is inside LlamaIndex or another library.

· 3 min read · YTAPI

Code that fetched YouTube transcripts fine before mid-2025 now stops on the first call:

AttributeError: type object 'YouTubeTranscriptApi' has no attribute 'get_transcript'

The same happens with list_transcripts and get_transcripts. If you created an instance first, the message says 'YouTubeTranscriptApi' object has no attribute 'get_transcript' instead. Your code didn't change: the library did.

We make YTAPI, a hosted transcript API, and ran into this error while testing LlamaIndex's YouTube reader for another post. Everything below was run on October 14, 2026 with youtube-transcript-api 1.2.4, the latest release.

Why it broke

youtube-transcript-api 1.0.0 (March 2025) replaced the static methods with methods on an instance, and kept the old ones as deprecated. 1.2.0 (July 2025) removed them. Any project that pins youtube-transcript-api loosely, or not at all, picks up 1.2.x on its next install and breaks.

The maintainer's reason for removing them: people passed a proxy config to the constructor and then called the static methods, which never saw it, so their proxies were silently ignored.

The fix

Before 1.2Now
YouTubeTranscriptApi.get_transcript(video_id)YouTubeTranscriptApi().fetch(video_id).to_raw_data()
YouTubeTranscriptApi.list_transcripts(video_id)YouTubeTranscriptApi().list(video_id)
YouTubeTranscriptApi.get_transcripts(ids)a loop over fetch()

In code:

from youtube_transcript_api import YouTubeTranscriptApi

ytt_api = YouTubeTranscriptApi()  # pass proxy_config=... here if you use one

transcript = ytt_api.fetch("dQw4w9WgXcQ", languages=["en"])
raw = transcript.to_raw_data()  # the list of dicts get_transcript() returned

for track in ytt_api.list("dQw4w9WgXcQ"):
    print(track.language_code, track.is_generated)

Create the instance once and reuse it: it keeps one HTTP session, and it's where your proxy settings live.

The errors right after the fix

fetch() returns a FetchedTranscript object, not a list of dicts. Code written for the old return value fails in two more places. We ran both:

>>> transcript = ytt_api.fetch("dQw4w9WgXcQ")
>>> transcript[0]
FetchedTranscriptSnippet(text='[♪♪♪]', start=1.36, duration=1.68)
>>> transcript[0]["text"]
TypeError: 'FetchedTranscriptSnippet' object is not subscriptable
>>> json.dumps(transcript)
TypeError: Object of type FetchedTranscript is not JSON serializable

Either use attributes (snippet.text, snippet.start, snippet.duration), or call .to_raw_data() once and keep the rest of your code as it was. Indexing, len() and iterating still work on the object itself.

Pinning the old version instead

If you can't change the calling code today, pin the last release that still has the old methods:

pip install "youtube-transcript-api<1.2"

That's 1.1.1. Its DeprecationWarning is hidden by default, so nothing will tell you you're on borrowed time. Today it fetches transcripts with exactly the same code as 1.2.4 (we compared the two), but when YouTube changes something, the fix will only land in new releases. Treat the pin as a stopgap.

When the old call is inside a library

Often the call isn't in your code. LlamaIndex's YoutubeTranscriptReader is one: version 0.6.0 of llama-index-readers-youtube-transcript, the latest on PyPI, still calls YouTubeTranscriptApi.get_transcript, and so does the reader on LlamaIndex's main branch as of today. A fresh install fails like this:

  File ".../llama_index/readers/youtube_transcript/base.py", line 50, in load_data
    transcript_chunks = YouTubeTranscriptApi.get_transcript(
AttributeError: type object 'YouTubeTranscriptApi' has no attribute 'get_transcript'

Pinning youtube-transcript-api<1.2 next to it works. So does replacing the reader with a few lines that do the same job on the new API:

from llama_index.core import Document
from youtube_transcript_api import (
    NoTranscriptFound,
    TranscriptsDisabled,
    VideoUnavailable,
    YouTubeTranscriptApi,
)

ytt_api = YouTubeTranscriptApi()  # pass proxy_config=... here if you use one


def load_youtube(video_ids, languages=("en",)):
    """What YoutubeTranscriptReader.load_data did, on the 1.x API.
    Videos without a transcript are skipped; a block (RequestBlocked) still
    raises, since every video after it would fail the same way."""
    docs = []
    for video_id in video_ids:
        try:
            transcript = ytt_api.fetch(video_id, languages=languages)
        except (TranscriptsDisabled, NoTranscriptFound, VideoUnavailable) as e:
            print(f"skipped {video_id}: {type(e).__name__}")
            continue
        text = "\n".join(snippet.text for snippet in transcript)
        docs.append(Document(text=text, id_=video_id, metadata={"video_id": video_id}))
    return docs

We ran it with llama-index-core 0.14.25 and got one Document per video, as the reader used to return. Unlike the old reader, it skips a video without captions instead of failing the whole list. The same error has been reported against other projects, such as Meta's synthetic-data-kit and Agno's YouTube tools; the fix is the same wherever the call lives.

The next error: RequestBlocked

Once the code runs, the next thing many people hit is YouTube refusing the request. It happened to us while writing this post: after about fifteen requests in ten minutes from one development machine, every fetch started failing with:

youtube_transcript_api._errors.RequestBlocked:
Could not retrieve a transcript for the video https://www.youtube.com/watch?v=...

The message lists the usual causes: too many requests from one IP, or an IP that belongs to a cloud provider. On a server it's often there from the first request. We've written up what to do about it:

Skipping the blocks

If you'd rather not deal with blocks at all, YTAPI fetches transcripts through our own proxy network and gives them back as JSON, Markdown with timestamps, SRT or plain text. A transcript costs 1 credit, failed requests are free, and new accounts get 200 credits:

# pip install ytapi-sdk
import os
from ytapi import YTAPI

api = YTAPI(api_key=os.environ["YTAPI_KEY"])
transcript = api.get_transcript("dQw4w9WgXcQ")  # segments with start times

FAQ

Which version do I have?

Run pip show youtube-transcript-api. Anything from 1.2.0 on has no get_transcript.

Is fetch() slower than get_transcript() was?

No. In 1.1.1, get_transcript() was a shortcut that created an instance and called the same code. Reusing one instance for many videos is a little faster, since it keeps one HTTP session.

Where did get_transcripts() go?

It was removed without a replacement; a loop over fetch() does the job. The old method returned a pair: the transcripts by video ID, and the IDs that failed. If your code used that second list, collect the failures in your loop, and catch errors per video so one video without captions doesn't stop the rest.

Published October 14, 2026. Tested with youtube-transcript-api 1.2.4, llama-index-readers-youtube-transcript 0.6.0 and llama-index-core 0.14.25 on Python 3.10.