tonhowtf/omniget · error
Could not extract user and post_id from URL
Error message
Could not extract user and post_id from URL
What it means
native_get_media_info() for Bluesky extracts the handle and post id (rkey) from the URL via extract_user_and_post(). If the URL doesn't match the expected post-URL shape, it returns this error before making any network call. It's a URL-shape validation guard on the input link.
Solutions
- Use the full post URL copied from Bluesky: https://bsky.app/profile/<handle>/post/<rkey>.
- Normalize custom-domain links to bsky.app form before passing them in.
- Extend extract_user_and_post() to handle AT-URI form (at://...) or extra URL segments.
Example fix
// before let url_in = "https://bsky.app/profile/alice.bsky.social"; // profile URL -> error // after let url_in = "https://bsky.app/profile/alice.bsky.social/post/3kx2abc123"; // full post URL
Defensive patterns
Strategy: validation
Validate before calling
fn looks_like_bluesky_post(url: &str) -> bool {
url.contains("bsky.app/profile/") && url.contains("/post/")
}
if !looks_like_bluesky_post(url) { return Err(anyhow!("expected a bsky.app post URL")); } Type guard
fn parse_bsky_post(url: &str) -> Option<(String, String)> {
let rest = url.strip_prefix("https://bsky.app/profile/")?;
let mut it = rest.split('/');
let user = it.next()?.to_string();
let (_post, rkey) = (it.next()?, it.next()?.to_string());
Some((user, rkey))
} Try / catch
match get_media_info(url).await {
Err(e) if e.to_string().contains("Could not extract user and post_id") => {
eprintln!("use full post URL: https://bsky.app/profile/<handle>/post/<rkey>");
Err(e)
}
other => other,
} Prevention
- Always pass full post URLs containing /profile/<handle>/post/<rkey>.
- Reject profile or search pages before calling get_media_info.
- Normalize custom-domain links to bsky.app format first.
When it happens
Trigger: get_media_info() -> native_get_media_info() with a bluesky URL that extract_user_and_post() cannot parse — missing /post/<rkey> segment, wrong domain, profile or search URL, or extra query fragments.
Common situations: Passing https://bsky.app/profile/<user> (profile page) instead of a post URL; a shortened/custom-domain link; a URL with a trailing locale or query string the regex doesn't tolerate.
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
- Unsupported link
- Could not extract YouTube video ID
- Could not extract user and post_id from URL
- InvalidRequest
- Could not extract clip slug
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/0be418593977c541.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/platforms/bluesky.rs:33
client: reqwest::Client,
}
impl Default for BlueskyDownloader {
fn default() -> Self {
Self::new()
}
}
impl BlueskyDownloader {
async fn fallback_ytdlp(&self, url: &str) -> anyhow::Result<MediaInfo> {
let ytdlp_path = crate::core::ytdlp::ensure_ytdlp().await?;
let json = crate::core::ytdlp::get_video_info(&ytdlp_path, url, &[]).await?;
crate::platforms::generic_ytdlp::GenericYtdlpDownloader::parse_video_info(&json)
}
async fn native_get_media_info(&self, url: &str) -> anyhow::Result<MediaInfo> {
let (user, post_id) = Self::extract_user_and_post(url)
.ok_or_else(|| anyhow!("Could not extract user and post_id from URL"))?;
let json = self.fetch_post(&user, &post_id).await?;
let embed = json
.pointer("/thread/post/embed")
.ok_or_else(|| anyhow!("Post does not contain media"))?;
let media = extract_media(embed).ok_or_else(|| anyhow!("Unsupported media type"))?;
let filename_base = format!("bluesky_{}_{}", sanitize_filename::sanitize(&user), post_id);
match media {
BlueskyMedia::Video { hls_url } => Ok(MediaInfo {
title: filename_base,
author: user,
platform: "bluesky".to_string(),
duration_seconds: None,
thumbnail_url: None,View on GitHub (pinned to 8600b91f42)