Skip to content

fix(transcript): answer a YouTube sign-in request with its cause, not TEMPORARY #295

Closed

Description

@pascalandy

The problem

When YouTube asks yt-dlp to sign in ("confirm you're not a bot"), ncly transcript run youtube answers TEMPORARY with exit 75 and the hint "Run the same call again later". Exit 75 lets an agent repeat the call on its own, and the same IP keeps getting the same refusal. The answer never says that cookies, the browser = "arc" setting of transcript, would get past it.

What we saw

During the macOS Verify of #289 (#266) on the mbp, at 2bc3674, Fake key of transcript-run.md failed twice, at 21:50 and at 22:08 America/Montreal, with exit 75 TEMPORARY. om1, on the same network, passed the same step at 21:50. A run with --verbose showed yt-dlp's diagnostic:

transcript: Starting the audio download...
yt-dlp failed: WARNING: [youtube] EIEc43CxIvY: Unable to download webpage: HTTP Error 429: Too Many Requests (caused by <HTTPError 429: Too Many Requests>) WARNING: [youtube] Unable to fetch GVS PO Token for web client: Missing required Visitor Data. You may need to pass Visitor Data with --extractor-args "youtube:visitor_data=XXX" ERROR: [youtube] EIEc43CxIvY: Sign in to confirm you’re not a bot. Use --cookies-from-browser or --cookies for the authentication. See https://github.com/yt-dlp/yt-dlp/wiki/FAQ#how-do-i-pass-cookies-to-yt-dlp for how to manually pass cookies. Also see https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies for tips on effectively exporting YouTube cookies
{"ok":false,"contract_version":1,"run_id":"verify-fake-diag","results":[{"ok":false,"output_dir":null,"transcript":null,"url":"https://www.youtube.com/watch?v=EIEc43CxIvY","errors":[{"code":"TEMPORARY","message":"YouTube did not answer for https://www.youtube.com/watch?v=EIEc43CxIvY, so no audio was downloaded.","hint":"Run the same call again later."}]}],"errors":[{"code":"TEMPORARY","message":"Some work failed for a reason that may pass.","hint":"Run the same command again."}]}

The final ERROR is the sign-in request. The 429 is a WARNING before it.

What exists today

At 4d61b56, extensions/transcript/python/youtube.py lines 38 to 43 define YTDLP_TEMPORARY, which matches HTTP Error (?:429|5\d\d) anywhere in the diagnostic. Lines 145 to 149 raise YtDlpError with temporary from a search over the whole diagnostic (line 147), so the warning wins over the final error. transcript.py lines 115 to 119 then map it to download_temporary, which spec/protocol.md line 58 maps to TEMPORARY.

Decision

A sign-in request answers TRANSCRIPT_DOWNLOAD_FAILED (exit 1), and its hint names the browser setting of transcript. Do not add an error code. No refusal that waiting does not fix gets exit 75.

Pascal decided this on 2026-11-03, after the reality check.

Acceptance rules

  1. The final ERROR record of the yt-dlp diagnostic decides the code. A WARNING before it does not.
  2. The classification reads the raw diagnostic, before _clean_subprocess_diagnostic collapses it and cuts it to 2,000 characters (youtube.py lines 152-161).
  3. A final ERROR that names a network failure of YTDLP_TEMPORARY (youtube.py lines 37-42), such as HTTP 429, HTTP 5xx, or Connection refused, stays TEMPORARY (exit 75).
  4. A final ERROR that asks for a sign-in answers TRANSCRIPT_DOWNLOAD_FAILED.
  5. Another final ERROR answers TRANSCRIPT_DOWNLOAD_FAILED, so that an agent does not retry it on its own.
  6. A diagnostic with no ERROR record keeps the classification of today.

Check

NCLY_TEST_DOWNLOAD skips the classification (python/testing/launcher.py lines 82-102), so the tests use a stub yt-dlp. Tests prove these cases:

  • The diagnostic above: TRANSCRIPT_DOWNLOAD_FAILED with the browser hint
  • A sign-in ERROR after more than 2,000 characters of warnings: TRANSCRIPT_DOWNLOAD_FAILED
  • A final 429 ERROR, a final 503 ERROR, and a final Connection refused ERROR: TEMPORARY
  • An unknown final ERROR: TRANSCRIPT_DOWNLOAD_FAILED
  • Connection refused with no ERROR record: TEMPORARY, as today

just check passes.

Found outside the plan, by Cook 2.1 of brigade e3dd, during the Verify of #266. Out of Epic 13's scope.

by Opus-5.5 via Claude Code

Activity

  1. added
    1-needs-triageScope, approach, or direction needs evaluation
    2-type:bugExisting behavior is broken
    3-pty:p2Normal planned work; default when no priority is established
    on Oct 20, 2026
  2. added
    1-ready-for-agentValidated work, sufficiently specified for an autonomous agent
    1-wip-by-agentAn agent has started work on this issue
    and removed
    1-needs-triageScope, approach, or direction needs evaluation
    1-ready-for-agentValidated work, sufficiently specified for an autonomous agent
    on Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    2-type:bugExisting behavior is broken3-pty:p2Normal planned work; default when no priority is established

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions