tonhowtf/omniget · error
Could not extract tweet ID
Error message
Could not extract tweet ID
What it means
native_get_media_info calls Self::extract_tweet_id(url), which parses the tweet ID out of the URL; it returns Option and this error is raised (via ok_or_else) when the result is None. It means the URL was accepted by can_handle (a twitter.com/x.com/vxtwitter.com/fixvx.com host) but its path does not contain a recognizable numeric tweet ID.
Solutions
- Ensure the URL contains /status/<numeric-id> (e.g. https://x.com/<user>/status/1234567890123456789).
- Resolve any shortener/redirect links to the final x.com or twitter.com URL before calling get_media_info.
- Validate the URL with a regex like /status/(\d+) before invoking the downloader to give users a clearer message.
- If the URL uses vxtwitter/fixvx rewriting, confirm the path still preserves the status/ID segment.
- Update extract_tweet_id if Twitter introduced a new valid URL format it no longer matches.
Example fix
// before
let url = "https://x.com/someuser"; // no status path
downloader.get_media_info(url).await?;
// after
let re = regex::Regex::new(r"/status/(\d+)").unwrap();
if !re.is_match(&url) {
anyhow::bail!("not a tweet permalink: {}", url);
}
let info = downloader.get_media_info(url).await?; Defensive patterns
Strategy: validation
Validate before calling
static TWEET_ID_RE: once_cell::sync::Lazy<regex::Regex> =
once_cell::sync::Lazy::new(|| regex::Regex::new(r"/status/(\d+)").unwrap());
fn is_tweet_permalink(url: &str) -> bool {
TWEET_ID_RE.is_match(url)
}
// call is_tweet_permalink(url) before get_media_info Type guard
fn is_tweet_permalink(url: &str) -> bool {
regex::Regex::new(r"https?://(www\.)?(x|twitter|vxtwitter|fixvx)\.com/\S+/status/\d+")
.map(|re| re.is_match(url))
.unwrap_or(false)
} Try / catch
match downloader.get_media_info(url).await {
Err(e) if e.to_string().contains("Could not extract tweet ID") => {
eprintln!("'{url}' is not a tweet permalink; expected x.com/<user>/status/<id>");
}
other => other?,
} Prevention
- Always resolve shortener URLs to their final destination first.
- Reject non-permalink Twitter URLs (profiles, search, home) at input validation time.
- Require the /status/<numeric-id> segment before passing URLs to the downloader.
- Handle vxtwitter/fixvx links by normalizing them to x.com permalinks.
When it happens
Trigger: Calling get_media_info with a Twitter-domain URL that has no /status/<digits> segment — e.g. profile URLs (https://x.com/user), status with non-numeric or truncated ID, URLs like https://x.com/user/status (missing ID), localized/redirect paths, or alternate front-end hosts (vxtwitter/fixvx) with rewritten paths.
Common situations: Users pasting profile or home-timeline links instead of a tweet link; URL shortener output that hasn't been resolved; malformed copy-paste that truncates the ID; code feeding can_handle-approved URLs without validating the status path; regex in extract_tweet_id lagging behind new URL shapes.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- Could not extract tweet ID
- Could not extract user and post_id from URL
- não reconheci esse perfil ou coleção
- Age-restricted content
- chave de verificacao do X nao encontrada
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/4763bc30e09359c2.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/platforms/twitter.rs:900
async fn fallback_ytdlp(&self, url: &str) -> anyhow::Result<MediaInfo> {
let ytdlp_path = crate::core::ytdlp::ensure_ytdlp().await?;
let mut extra_flags = vec![
"--referer".to_string(),
"https://x.com/".to_string(),
"--add-headers".to_string(),
"Referer:https://x.com/".to_string(),
];
if let Some(cookie) = Self::auth_cookie_string() {
extra_flags.push("--add-headers".to_string());
extra_flags.push(format!("Cookie:{}", cookie));
}
let json = crate::core::ytdlp::get_video_info(&ytdlp_path, url, &extra_flags).await?;
crate::platforms::generic_ytdlp::GenericYtdlpDownloader::parse_video_info(&json)
}
async fn native_get_media_info(&self, url: &str) -> anyhow::Result<MediaInfo> {
let tweet_id =
Self::extract_tweet_id(url).ok_or_else(|| anyhow!("Could not extract tweet ID"))?;
tracing::debug!(
"[twitter] native_get_media_info tweet_id={} url={}",
tweet_id,
url
);
let filename_base = format!("twitter_{}", tweet_id);
let media_items = match self.try_graphql(&tweet_id).await {
Ok(items) => items,
Err(graphql_err) => {
tracing::warn!(
"[twitter] graphql lookup failed for tweet_id={}: {}",
tweet_id,
graphql_err
);
match self.request_syndication(&tweet_id).await {
Ok(syndication) => match Self::extract_syndication_media(&syndication) {View on GitHub (pinned to 8600b91f42)