tonhowtf/omniget · error · anyhow::Error

Twitter extraction failed. native=

Error message

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

What it means

get_media_info tries native Twitter extraction first and falls back to yt-dlp; this error is raised only when BOTH strategies fail, aggregating both underlying messages into one string. The native error and the yt-dlp error are the real diagnostic payload embedded in the formatted message.

Solutions

  1. Read both embedded errors: fix the native cause first (usually auth/rate-limit or unavailable tweet) as indicated by native='...'.
  2. Update yt-dlp to the latest version since stale binaries fail on current X responses.
  3. Verify the URL is a valid tweet URL extractable to a tweet ID.
  4. Retry later if the errors indicate rate limiting (HTTP 429) from Twitter endpoints.
  5. Ensure yt-dlp is installed and on PATH for the fallback path to be meaningful.

Example fix

// before
Err(anyhow!("Twitter extraction failed. native='{}'; ytdlp='{}'", native_err, fallback_err))
// after
#[derive(Debug, thiserror::Error)]
enum TwitterExtractError {
    #[error("native extraction failed: {0}")] Native(#[source] anyhow::Error),
    #[error("yt-dlp fallback failed: {0}")] Ytdlp(#[source] anyhow::Error),
}
return Err(TwitterExtractError::Ytdlp(fallback_err).into()); // preserves both causes as a chain
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight checks before calling get_media_info
fn preflight_ok(url: &str, ytdlp_path: &str) -> Result<(), String> {
    if extract_tweet_id(url).is_none() { return Err("not a tweet URL".into()); }
    if !std::path::Path::new(ytdlp_path).exists() { return Err("yt-dlp not found".into()); }
    Ok(())
}

Try / catch

match get_media_info(url).await {
    Ok(info) => download(info),
    Err(e) => {
        let msg = e.to_string();
        if msg.contains("429") { schedule_retry_with_backoff(); }
        else if msg.contains("ytdlp=") && msg.contains("not found") { prompt_ytdlp_install(); }
        else { show_extraction_failed(&msg); }
    }
}

Prevention

When it happens

Trigger: native_get_media_info fails (bad URL, GraphQL/syndication blocked, tweet unavailable) AND the subsequent yt-dlp fallback also fails (yt-dlp missing/outdated, network failure, unsupported tweet) — both in one get_media_info call.

Common situations: Twitter/X restricting guest access to GraphQL so native fails, combined with an outdated yt-dlp binary that also fails on new X layouts; offline environments; rate limiting hitting both paths; malformed tweet URLs.

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/2080efc808876e48. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/src/platforms/twitter/mod.rs:830

        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)