{"record":{"id":"292785d2211a55b0","repo":"tonhowtf/omniget","slug":"token-sem-value","errorCode":null,"errorMessage":"Token sem value","messagePattern":"Token sem value","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/platforms/twitch.rs","lineNumber":243,"sourceCode":"\n        let json: serde_json::Value = response.json().await?;\n\n        let token_obj = json\n            .as_array()\n            .and_then(|arr| arr.first())\n            .and_then(|r| r.pointer(\"/data/clip/playbackAccessToken\"))\n            .ok_or_else(|| anyhow!(\"Access token not available for clip: {}\", slug))?;\n\n        let signature = token_obj\n            .get(\"signature\")\n            .and_then(|v| v.as_str())\n            .ok_or_else(|| anyhow!(\"Token sem signature\"))?\n            .to_string();\n\n        let value = token_obj\n            .get(\"value\")\n            .and_then(|v| v.as_str())\n            .ok_or_else(|| anyhow!(\"Token sem value\"))?\n            .to_string();\n\n        Ok(AccessToken { signature, value })\n    }\n\n    fn build_authenticated_url(source_url: &str, token: &AccessToken) -> String {\n        format!(\n            \"{}?sig={}&token={}\",\n            source_url,\n            urlencoding::encode(&token.signature),\n            urlencoding::encode(&token.value),\n        )\n    }\n}\n\n#[async_trait]\nimpl PlatformDownloader for TwitchClipsDownloader {\n    fn name(&self) -> &str {","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/platforms/twitch.rs#L225-L261","documentation":"Thrown in fetch_access_token when the Twitch playback access token JSON has a signature but no string \"value\" field. Both signature and value are required to build the authenticated playback URL (AccessToken struct), so the library fails fast with this Portuguese message (\"Token without value\").","triggerScenarios":"Twitch's GQL PlaybackAccessToken response object contains signature but the \"value\" key is missing, null, or not a string.","commonSituations":"Twitch schema changes; partial/degraded API responses; clip restricted so Twitch returns a truncated token object.","solutions":["Log the raw token_obj JSON to see actual keys","Validate the clip exists and is not restricted before requesting a token","Update parsing to match the current Twitch GQL schema","Retry once — intermittent Twitch responses can omit fields"],"exampleFix":"// before\nlet value = token_obj.get(\"value\").and_then(|v| v.as_str()).ok_or_else(|| anyhow!(\"Token sem value\"))?.to_string();\n// after\nlet value = token_obj.get(\"value\")\n    .and_then(|v| v.as_str())\n    .ok_or_else(|| anyhow!(\"Token sem value; response keys: {:?}\", token_obj.as_object().map(|o| o.keys().collect::<Vec<_>>())))?;\n.to_string();","handlingStrategy":"validation","validationCode":"fn has_valid_token(obj: &serde_json::Value) -> bool {\n    obj.get(\"signature\").and_then(|v| v.as_str()).is_some()\n        && obj.get(\"value\").and_then(|v| v.as_str()).is_some()\n}","typeGuard":"fn is_string_field(v: &serde_json::Value, key: &str) -> Option<&str> {\n    v.get(key).and_then(|x| x.as_str())\n}","tryCatchPattern":null,"preventionTips":["Validate both signature and value in one guard before constructing AccessToken","Log response keys when parsing fails","Retry once on partial responses","Track Twitch API schema changes proactively"],"tags":["twitch","missing-field","api-response","rust"],"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"}