{"record":{"id":"bf602f7884f968cc","repo":"tonhowtf/omniget","slug":"vod-n-o-encontrado-ou-j-expirou","errorCode":null,"errorMessage":"VOD não encontrado (ou já expirou): {}","messagePattern":"VOD não encontrado \\(ou já expirou\\): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/twitch/gql.rs","lineNumber":222,"sourceCode":"        let data = self.query(&q).await?;\n        let u = data.get(\"user\").filter(|v| !v.is_null());\n        let u = u.ok_or_else(|| anyhow!(\"canal não encontrado: {}\", login))?;\n        Ok(Channel {\n            id: str_at(u, \"id\"),\n            login: str_at(u, \"login\"),\n            display_name: str_at(u, \"displayName\"),\n            avatar: str_at(u, \"profileImageURL\"),\n        })\n    }\n\n    pub async fn video(&self, id: &str) -> anyhow::Result<VideoInfo> {\n        let q = format!(\n            r#\"{{ video(id: \"{}\") {{ id title lengthSeconds createdAt owner {{ login displayName }} }} }}\"#,\n            escape(id)\n        );\n        let data = self.query(&q).await?;\n        let v = data.get(\"video\").filter(|v| !v.is_null());\n        let v = v.ok_or_else(|| anyhow!(\"VOD não encontrado (ou já expirou): {}\", id))?;\n        Ok(VideoInfo {\n            id: str_at(v, \"id\"),\n            title: str_at(v, \"title\"),\n            channel: v\n                .pointer(\"/owner/login\")\n                .and_then(|x| x.as_str())\n                .unwrap_or_default()\n                .to_string(),\n            channel_display: v\n                .pointer(\"/owner/displayName\")\n                .and_then(|x| x.as_str())\n                .unwrap_or_default()\n                .to_string(),\n            duration_seconds: v.get(\"lengthSeconds\").and_then(num).unwrap_or_default(),\n            created_at: str_at(v, \"createdAt\"),\n            clip_offset: None,\n            clip_duration: None,\n        })","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/twitch/gql.rs#L204-L240","documentation":"video() looks up a VOD by id via GraphQL and throws when data.video is missing or null. Twitch returns null both for unknown ids and for VODs that expired or were deleted, so the message explicitly mentions expiry — a frequent cause given Twitch's 14/30/60-day retention limits.","triggerScenarios":"Calling gql.video(id) (directly or via clip_video / resolve_chat_target) with an id whose VOD no longer exists: expired after the retention window, deleted by the broadcaster, removed by DMCA, or a mistyped id.","commonSituations":"Trying to download chat for an old VOD past its subscriber retention period; DMCA-deleted VODs; wrong id (using a slug or timestamp instead of the numeric VOD id); turbo/sub-only VODs accessed without auth.","solutions":["Open https://www.twitch.tv/videos/<id> to confirm the VOD still exists","Check whether the VOD expired per the channel's retention window — it cannot be recovered","Correct the VOD id (must be the numeric id, not a title/slug)","For sub-only VODs, ensure proper authentication cookies are supplied if supported"],"exampleFix":"// before\nlet v = gql.video(\"1234567890\").await?; // expired VOD\n// after\nlet v = match gql.video(\"1234567890\").await {\n    Ok(v) => v,\n    Err(e) if e.to_string().contains(\"expirou\") => {\n        eprintln!(\"VOD unavailable/expired; pick another\");\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n};","handlingStrategy":"validation","validationCode":"let id = input.trim();\nif !id.chars().all(|c| c.is_ascii_digit()) {\n    eprintln!(\"VOD id must be numeric, got: {id}\");\n    return Ok(());\n}\n// Optionally: check twitch.tv/videos/{id} is still live before calling.","typeGuard":null,"tryCatchPattern":"match gql.video(id).await {\n    Err(e) if e.to_string().contains(\"expirou\") => {\n        eprintln!(\"VOD {id} is gone (expired/deleted); cannot recover\");\n        Ok(())\n    }\n    other => other,\n}","preventionTips":["Only use the numeric VOD id, not slugs or titles","Check retention windows (14/30/60 days) before scheduling downloads","Act quickly — expired or DMCA-removed VODs are unrecoverable","For sub-only VODs, supply valid authentication if supported"],"tags":["twitch","gql","vod","not-found","expired"],"backgroundTag":"entity-not-found","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"}