unslothai/unsloth · warning · HTTPException

That is not a YouTube video link.

Error message

That is not a YouTube video link.

What it means

400 from POST /api/youtube/transcript: extract_video_id(request.url) returned None, so the submitted URL does not contain a recognizable YouTube video id (watch?v=, youtu.be/<id>, shorts, embed forms). The parser is strict about the hosts and query shapes it accepts.

Source

Thrown at studio/backend/routes/youtube.py:57

    videoId: str
    url: str
    title: str
    author: str
    lengthSeconds: int
    language: str
    languageCode: str
    isGenerated: bool
    text: str
    truncated: bool


@router.post("/transcript", response_model = TranscriptResponse)
async def get_transcript(
    request: TranscriptRequest, current_subject: str = Depends(get_current_subject)
) -> TranscriptResponse:
    video_id = extract_video_id(request.url)
    if video_id is None:
        raise HTTPException(status_code = 400, detail = "That is not a YouTube video link.")

    try:
        transcript = await fetch_transcript(video_id, request.languages)
    except TranscriptUnavailable as error:
        raise HTTPException(status_code = 422, detail = str(error)) from error
    except httpx.HTTPError as error:
        logger.warning(f"YouTube transcript fetch failed for {video_id}: {error}")
        raise HTTPException(
            status_code = 502,
            detail = "Could not reach YouTube.",
        ) from error

    return TranscriptResponse(
        videoId = transcript.video_id,
        url = watch_url(transcript.video_id),
        title = transcript.title,
        author = transcript.author,
        lengthSeconds = transcript.length_seconds,

View on GitHub (pinned to 203007d190)

Solutions

  1. Use a canonical URL: https://www.youtube.com/watch?v=<11-char-id> or https://youtu.be/<id>.
  2. Validate client-side before posting (regex for the 11-char id pattern).
  3. If a legitimate YouTube URL shape fails, extract the id yourself and build the canonical form before sending.

Example fix

// before
await api.post('/youtube/transcript', { url: rawPaste });

// after
const m = rawPaste.match(/(?:v=|youtu\.be\/|shorts\/)([\w-]{11})/);
if (!m) return showError('Paste a YouTube video link');
await api.post('/youtube/transcript', { url: `https://www.youtube.com/watch?v=${m[1]}` });
Defensive patterns

Strategy: validation

Validate before calling

const YT = /(?:youtube\.com\/(?:watch\?v=|shorts\/|embed\/)|youtu\.be\/)([\w-]{11})/;
function extractOrReject(url) {
  const m = url?.match(YT);
  if (!m) throw new ValidationError('That is not a YouTube video link.');
  return m[1];
}

Type guard

function isYouTubeUrl(u: string): boolean {
  try { const h = new URL(u).hostname; return h === 'youtu.be' || h.endsWith('youtube.com'); }
  catch { return false; }
}

Try / catch

try { await postTranscript(url); }
catch (e) { if (e?.status === 400) showFieldError('Paste a YouTube video link (watch?v=… or youtu.be/…)'); else throw e; }

Prevention

When it happens

Trigger: Posting a channel or playlist URL, a bare video id without a URL, a clipboard artifact ('https://youtube.com/watch?v=abc '), a different service's link (vimeo/tiktok), or a URL with the v param stripped by a chat client's link unfurler.

Common situations: Paste-from-chat mangling; users pasting a search-results URL; frontend not validating before submit.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/783a067670025e8b. Report an issue: GitHub.