crewAIInc/crewAI · error · ValueError

Invalid YouTube URL: {video_url}

Error message

Invalid YouTube URL: {video_url}

What it means

ValueError from the video loader's _extract_video_id returning None — the URL does not contain a parseable YouTube video ID. The static helper matches the standard watch?v=, youtu.be/, /shorts/, and embed URL shapes; anything else (including channel URLs) yields None and trips this check before any network call.

Source

Thrown at lib/crewai-tools/src/crewai_tools/rag/loaders/youtube_video_loader.py:39

            LoaderResult with transcript content

        Raises:
            ImportError: If required YouTube libraries aren't installed
            ValueError: If the URL is not a valid YouTube video URL
        """
        try:
            from youtube_transcript_api import YouTubeTranscriptApi
        except ImportError as e:
            raise ImportError(
                "YouTube support requires youtube-transcript-api. "
                "Install with: uv add youtube-transcript-api"
            ) from e

        video_url = source.source
        video_id = self._extract_video_id(video_url)

        if not video_id:
            raise ValueError(f"Invalid YouTube URL: {video_url}")

        metadata: dict[str, Any] = {
            "source": video_url,
            "video_id": video_id,
            "data_type": "youtube_video",
        }

        try:
            api = YouTubeTranscriptApi()
            transcript_list = api.list(video_id)

            try:
                transcript = transcript_list.find_transcript(["en"])
            except Exception:
                try:
                    transcript = transcript_list.find_generated_transcript(["en"])
                except Exception:
                    transcript = next(iter(transcript_list))

View on GitHub (pinned to 754d7323be)

Solutions

  1. Use a canonical video URL: https://www.youtube.com/watch?v=VIDEOID or https://youtu.be/VIDEOID with an 11-character ID.
  2. For channels, switch to the YouTube channel loader.
  3. Pre-validate with your own extraction (e.g. regex for [\w-]{11} after v= or youtu.be/) before calling load.
  4. Log the exact URL received — invisible truncation or HTML entity encoding (& instead of &) is a frequent culprit.

Example fix

# before
loader.load(SourceContent(path="https://www.youtube.com/@handle"))  # not a video

# after
loader.load(SourceContent(path="https://www.youtube.com/watch?v=dQw4w9WgXcQ"))
Defensive patterns

Strategy: validation

Validate before calling

import re

VIDEO_ID = re.compile(r"(?:[?&]v=|youtu\.be/|/shorts/|/embed/)([A-Za-z0-9_-]{11})")

def extract_video_id(url: str) -> str | None:
    m = VIDEO_ID.search(url)
    return m.group(1) if m else None

def is_video_url(url: str) -> bool:
    return extract_video_id(url) is not None

Try / catch

try:
    result = yt_video_loader.load(src)
except ValueError as e:
    if "Invalid YouTube URL" in str(e):
        log.warning("unparseable youtube url: %r", url)
        skip(src)
    raise

Prevention

When it happens

Trigger: Passing a channel URL (youtube.com/@handle) or playlist URL to the video loader; URLs where the ID parameter is empty or truncated (watch?v=); youtu.be links with extra path segments; URLs with malformed query strings that defeat parsing.

Common situations: Mixing up the video and channel loaders; LLM-generated URLs that look plausible but have malformed query params; URLs copy-pasted with the v parameter dropped by a truncating chat client; shortened share links mangled by markdown formatting.

Related errors


AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15). Data as JSON: /api/errors/20e92f47e25f9f82. Report an issue: GitHub.