tonhowtf/omniget · warning
Unsupported media type
Error message
Unsupported media type
What it means
Thrown in BlueskyDownloader::native_get_media_info when extract_media(embed) returns None. The post's embed exists but its `$type` is not one of the supported embed views (video, images, external Tenor GIF, recordWithMedia), or required fields (playlist, images.fullsize, external.uri) are missing/empty. It means the native parser cannot handle this post's media shape.
Solutions
- Rely on the yt-dlp fallback: get_media_info already falls back to yt-dlp when native parsing fails, so ensure yt-dlp is installed/up to date (crate::core::ytdlp::ensure_ytdlp).
- Verify the post actually contains downloadable media (video, images, or Tenor GIF) in a browser before treating it as a bug.
- Update the library/embed match arms in extract_media to handle the new $type.
- Surface a user-facing 'this post has no supported media' message instead of retrying.
Example fix
// before
let media = extract_media(embed).ok_or_else(|| anyhow!("Unsupported media type"))?;
// after
let Some(media) = extract_media(embed) else {
tracing::debug!(embed = ?embed, "unhandled bluesky embed; falling back");
return Err(anyhow!("Unsupported media type")); // get_media_info will try yt-dlp
}; Defensive patterns
Strategy: fallback
Validate before calling
let embed = json.pointer("/thread/post/embed");
let supported = embed
.and_then(|e| e.get("$type"))
.and_then(|t| t.as_str())
.map(|t| matches!(t, "app.bsky.embed.video#view" | "app.bsky.embed.images#view" | "app.bsky.embed.external#view" | "app.bsky.embed.recordWithMedia#view"))
.unwrap_or(false); Type guard
fn has_supported_embed(json: &serde_json::Value) -> bool {
json.pointer("/thread/post/embed/$type")
.and_then(|t| t.as_str())
.map(|t| t.ends_with("video#view") || t.ends_with("images#view") || t.ends_with("external#view") || t.ends_with("recordWithMedia#view"))
.unwrap_or(false)
} Try / catch
match downloader.get_media_info(url).await {
Ok(info) => download(info),
Err(e) if e.to_string().contains("Unsupported media type") => {
// post has no supported embed; inform user, don't retry
}
Err(e) => report(e),
} Prevention
- Only pass bsky.app post URLs that visibly contain video/images/GIF media
- Keep yt-dlp installed so the built-in fallback can handle exotic embeds
- Log the embed $type when this error occurs to spot new Bluesky embed kinds early
When it happens
Trigger: Calling get_media_info on a bsky.app post whose embed is e.g. app.bsky.embed.record#view (quote post without media), an unknown/new embed $type, an images embed whose fullsize URLs are absent, or an external embed pointing to a non-Tenor URI.
Common situations: Users paste links to quote-only posts, posts whose external link card is not Tenor, or new embed types Bluesky introduces that the extractor doesn't know; also posts where the CDN returns embed objects with unexpected fields.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Unsupported media type
- Could not extract user and post_id from URL
- Post does not contain media
- Bluesky API retornou HTTP
- Post not available
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/ae608aac33eb3666.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/platforms/bluesky.rs:41
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,
available_qualities: vec![VideoQuality {
label: "best".to_string(),
width: 0,
height: 0,
url: hls_url,
format: "hls".to_string(),
}],
media_type: MediaType::Video,View on GitHub (pinned to 8600b91f42)