{"record":{"id":"539b48b8f4d8c65c","repo":"tonhowtf/omniget","slug":"post-does-not-contain-media","errorCode":null,"errorMessage":"Post does not contain media","messagePattern":"Post does not contain media","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/platforms/bluesky.rs","lineNumber":39,"sourceCode":"    }\n}\n\nimpl BlueskyDownloader {\n    async fn fallback_ytdlp(&self, url: &str) -> anyhow::Result<MediaInfo> {\n        let ytdlp_path = crate::core::ytdlp::ensure_ytdlp().await?;\n        let json = crate::core::ytdlp::get_video_info(&ytdlp_path, url, &[]).await?;\n        crate::platforms::generic_ytdlp::GenericYtdlpDownloader::parse_video_info(&json)\n    }\n\n    async fn native_get_media_info(&self, url: &str) -> anyhow::Result<MediaInfo> {\n        let (user, post_id) = Self::extract_user_and_post(url)\n            .ok_or_else(|| anyhow!(\"Could not extract user and post_id from URL\"))?;\n\n        let json = self.fetch_post(&user, &post_id).await?;\n\n        let embed = json\n            .pointer(\"/thread/post/embed\")\n            .ok_or_else(|| anyhow!(\"Post does not contain media\"))?;\n\n        let media = extract_media(embed).ok_or_else(|| anyhow!(\"Unsupported media type\"))?;\n\n        let filename_base = format!(\"bluesky_{}_{}\", sanitize_filename::sanitize(&user), post_id);\n\n        match media {\n            BlueskyMedia::Video { hls_url } => Ok(MediaInfo {\n                title: filename_base,\n                author: user,\n                platform: \"bluesky\".to_string(),\n                duration_seconds: None,\n                thumbnail_url: None,\n                available_qualities: vec![VideoQuality {\n                    label: \"best\".to_string(),\n                    width: 0,\n                    height: 0,\n                    url: hls_url,\n                    format: \"hls\".to_string(),","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/platforms/bluesky.rs#L21-L57","documentation":"After fetching the post JSON, native_get_media_info() reads the JSON pointer /thread/post/embed. If the pointer is absent the post has no embedded media (plain text post, or embed in an unexpected place) and this error is returned. It distinguishes a successfully fetched but non-media post from a network/parsing failure.","triggerScenarios":"get_media_info() -> native_get_media_info() where fetch_post() succeeds but the returned AppView JSON has no thread.post.embed object — i.e. a text-only post, a repost, a deleted embed, or an embed-variant (e.g. record_with_media) at a different JSON path.","commonSituations":"User passes a text-only skeet URL; post is a repost of media living under a different pointer; Bluesky AppView changed the embed shape (recordWithMedia nesting) so the fixed pointer misses.","solutions":["Confirm the post actually contains an image or video (not text-only).","Handle record_with_media: also check thread.post.embed.record.embed / embeds array for nested media.","Return a clearer message distinguishing text-only posts from unsupported embed types.","Verify against the current AppView schema if Bluesky changed embed nesting."],"exampleFix":"// before\nlet embed = json.pointer(\"/thread/post/embed\").ok_or_else(|| anyhow!(\"Post does not contain media\"))?;\n// after\nlet embed = json.pointer(\"/thread/post/embed\")\n    .or_else(|| json.pointer(\"/thread/post/embed/record/embed\"))\n    .or_else(|| json.pointer(\"/thread/post/embeds/0\"))\n    .ok_or_else(|| anyhow!(\"Post does not contain media (text-only or unsupported embed type)\"))?;","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn embed_of(post_json: &serde_json::Value) -> Option<&serde_json::Value> {\n    post_json.pointer(\"/thread/post/embed\")\n        .or_else(|| post_json.pointer(\"/thread/post/embed/record/embed\"))\n        .or_else(|| post_json.pointer(\"/thread/post/embeds/0\"))\n}","tryCatchPattern":"match get_media_info(url).await {\n    Err(e) if e.to_string().contains(\"Post does not contain media\") => {\n        eprintln!(\"this post is text-only or uses an unsupported embed type\");\n        Err(e)\n    }\n    other => other,\n}","preventionTips":["Only pass posts known to contain images or video.","Handle reposts and record_with_media via nested JSON pointers.","Check for an 'embeds' array fallback since Bluesky supports multiple embed forms.","Re-validate pointer paths after Bluesky AppView schema updates."],"tags":["bluesky","media-extraction","unexpected-response"],"backgroundTag":"unexpected-response-shape","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}