tonhowtf/omniget · error

No media found in tweet

Error message

No media found in tweet

What it means

Raised when the tweet result __typename is "Tweet" (or TweetWithVisibilityResults) but media_arrays_from_tweet_result returns None — the tweet resolved successfully yet contains no media arrays (photos/videos) at the expected JSON paths. It specifically means 'this post exists but has no downloadable media', not that the post is unavailable.

Solutions

  1. Check the tweet actually contains media (photos/videos) before calling the extraction API.
  2. Log the tweet legacy entities to confirm whether media keys moved in the current schema.
  3. Update media_arrays_from_tweet_result to also check newer paths (e.g. views/media under the unified result).
  4. Return a distinct 'no media' typed error so callers can distinguish it from 'post unavailable'.

Example fix

// before
let media = Self::media_arrays_from_tweet_result(tweet_result)
    .ok_or_else(|| anyhow!("No media found in tweet"))?;
// after
let media = Self::media_arrays_from_tweet_result(tweet_result)
    .ok_or_else(|| TwitterError::NoMedia { tweet_id })?;
Defensive patterns

Strategy: validation

Validate before calling

// Check for media keys before extraction:
let has_media = tweet_result.pointer("/legacy/extended_entities/media").is_some()
    || tweet_result.pointer("/legacy/entities/media").is_some();
if !has_media {
    return Err(DisplayError::NoMedia);
}

Type guard

fn tweet_has_media(tweet_result: &serde_json::Value) -> bool {
    tweet_result.pointer("/legacy/extended_entities/media")
        .or_else(|| tweet_result.pointer("/legacy/entities/media"))
        .and_then(|v| v.as_array())
        .map(|a| !a.is_empty())
        .unwrap_or(false)
}

Try / catch

match extractor.fetch_media(tweet_url) {
    Err(e) if e.to_string() == "No media found in tweet" => {
        ui.show("This tweet contains no photos or videos.");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling the media-extraction API on a text-only tweet, a poll, or a link-only tweet; also when schema drift moves extended_entities/media keys so the extractor can't find them even though media exists.

Common situations: Users paste links to plain-text tweets expecting a download; deleted media (tweet edited/media removed); Twitter renaming legacy entities fields in newer GraphQL payloads.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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

Appendix: source

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

                    .and_then(|v| v.as_str())
                    .unwrap_or("");

                tracing::warn!(
                    "[twitter] graphql tombstone tweet_id={} reason='{}' tombstone_text='{}'",
                    tweet_id,
                    reason,
                    tombstone_text
                );

                if reason == "NsfwLoggedOut" || tombstone_text.starts_with("Age-restricted") {
                    return Err(anyhow!("Age-restricted content"));
                }

                Err(anyhow!("Post not available"))
            }
            "Tweet" | "TweetWithVisibilityResults" => {
                let media = Self::media_arrays_from_tweet_result(tweet_result)
                    .ok_or_else(|| anyhow!("No media found in tweet"))?;
                tracing::debug!(
                    "[twitter] graphql extracted {} media entries for tweet_id={}",
                    media.len(),
                    tweet_id
                );
                Ok(media)
            }
            _ => Err(anyhow!("Post not available")),
        }
    }

    fn extract_syndication_media(
        json: &serde_json::Value,
    ) -> anyhow::Result<Vec<serde_json::Value>> {
        let typename = json
            .get("__typename")
            .and_then(|v| v.as_str())
            .unwrap_or("");

View on GitHub (pinned to 8600b91f42)