tonhowtf/omniget · error

Twitter extraction failed. native=

Error message

Twitter extraction failed. native='{}'; ytdlp='{}'

What it means

get_media_info first tries the native Twitter extraction (guest-token GraphQL + syndication + HTML fallbacks) and, if that fails, falls back to shelling out to yt-dlp. This error is thrown only when BOTH strategies fail; the message embeds the native error and the yt-dlp error so the root cause of each path is preserved in a single aggregate error.

Solutions

  1. Read the two embedded sub-errors: fix the more actionable one first (native= usually points at tweet availability, ytdlp= at the tool or network).
  2. Update yt-dlp to the latest version (`yt-dlp -U` or re-run ensure_ytdlp) — Twitter extractors change frequently.
  3. Configure the X/Twitter auth cookie (auth_cookie_string) so both native and yt-dlp paths can access restricted content.
  4. Open the URL in a browser to confirm the tweet is public and still exists.
  5. If native= is a schema error, update the extract_* functions in twitter.rs; if ytdlp= is a launcher error, verify the yt-dlp binary path and network access.

Example fix

// before: retrying get_media_info blindly
let info = downloader.get_media_info(url).await?;
// after: check tweet availability and refresh yt-dlp first
if !tweet_exists_in_browser(url) {
    anyhow::bail!("tweet is deleted or private");
}
crate::core::ytdlp::ensure_ytdlp_updated().await?;
let info = downloader.get_media_info(url).await?;
Defensive patterns

Strategy: try-catch

Validate before calling

// before calling, ensure yt-dlp is available and URL is a live public tweet
let ytdlp_path = ensure_ytdlp().await?; // fails fast if binary cannot be procured
if !url.contains("/status/") {
    anyhow::bail!("not a tweet permalink");
}

Try / catch

match downloader.get_media_info(url).await {
    Err(e) if e.to_string().starts_with("Twitter extraction failed.") => {
        // both native and yt-dlp failed; parse embedded sub-errors
        let native = e.to_string();
        eprintln!("all strategies exhausted: {native}");
        // escalate to user: check tweet existence / update yt-dlp
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling get_media_info(url) where native_get_media_info returns Err (tweet unavailable, no media, tweet ID not extractable) AND fallback_ytdlp also returns Err (yt-dlp binary missing or failed to launch, yt-dlp out of date for current Twitter/X layout, network failure, or the tweet itself is gone/protected).

Common situations: Deleted or private tweets (both paths legitimately fail); outdated yt-dlp binary after a Twitter/X frontend change; missing or expired auth cookie so native extraction gets empty media and yt-dlp hits login walls; offline or blocked network; corrupted yt-dlp installation via ensure_ytdlp.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/87b8d7b7ff6b25cb. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/platforms/twitter.rs:764

        false
    }

    async fn get_media_info(&self, url: &str) -> anyhow::Result<MediaInfo> {
        match self.native_get_media_info(url).await {
            Ok(info) => Ok(info),
            Err(native_err) => {
                tracing::warn!(
                    "[twitter] native failed: {}, trying yt-dlp fallback",
                    native_err
                );
                match self.fallback_ytdlp(url).await {
                    Ok(info) => Ok(info),
                    Err(fallback_err) => {
                        tracing::warn!(
                            "[twitter] yt-dlp fallback failed after native error: {}",
                            fallback_err
                        );
                        Err(anyhow!(
                            "Twitter extraction failed. native='{}'; ytdlp='{}'",
                            native_err,
                            fallback_err
                        ))
                    }
                }
            }
        }
    }

    async fn download(
        &self,
        info: &MediaInfo,
        opts: &DownloadOptions,
        progress: mpsc::Sender<ProgressUpdate>,
    ) -> anyhow::Result<DownloadResult> {
        if let Some(quality) = info.available_qualities.first() {
            if quality.format == "ytdlp" {

View on GitHub (pinned to 8600b91f42)