{"record":{"id":"b88c484422e9d939","repo":"tonhowtf/omniget","slug":"empty-stream-url","errorCode":null,"errorMessage":"empty stream url","messagePattern":"empty stream url","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"info","filePath":"src/lib/study-music/player-store.svelte.ts","lineNumber":1565,"sourceCode":"    if (!this.audio) return;\n    const videoId = track.youtube_video_id;\n    if (!videoId) {\n      this.setError(\n        classifyPlayerError(\"video id ausente — track removed\", \"youtube\", track.id),\n      );\n      return;\n    }\n    this.loading = true;\n    await this.stopCurrentPlayback();\n    this.youtubeCurrentVideoId = videoId;\n    this.youtubeVideoUrl = null;\n    this.youtubeChapters = [];\n    this.youtubeSponsorBlockSegments = [];\n    this.youtubeRefreshFailureCount = 0;\n    try {\n      const { audio: audioUrl, video: videoUrl } =\n        await this.resolveYoutubeMedia(videoId);\n      if (!audioUrl) throw new Error(\"empty stream url\");\n      this.audio.crossOrigin = null;\n      this.audio.src = audioUrl;\n      this.youtubeVideoUrl = videoUrl;\n      void this.refreshYoutubeSponsorBlock(videoId);\n      await this.audio.play();\n      this.saveQueueNow();\n      this.updateMediaSessionMetadata(track);\n      void this.refreshDominantColor(track);\n      void pluginInvoke(\"study\", \"study:music:youtube:track_record_play\", {\n        video_id: videoId,\n      }).catch(() => {});\n    } catch (e) {\n      this.setError(classifyPlayerError(e, \"youtube\", track.id));\n    }\n  }\n\n  private cancelYoutubeRefresh() {\n    if (this.youtubeRefreshTimer) {","sourceCodeStart":1547,"sourceCodeEnd":1583,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src/lib/study-music/player-store.svelte.ts#L1547-L1583","documentation":"Raised by extract_graphql_media when the tweet result uses the \"Tweet\" or \"TweetWithVisibilityResults\" typename but Self::media_arrays_from_tweet_result returns None — the tweet parsed successfully yet contains no recognizable media arrays (extended_entities/entities/media or similar).","triggerScenarios":"Calling extract_graphql_media on a text-only tweet (no photos/videos/GIFs), or on a tweet whose media fields were stripped/renamed by a Twitter GraphQL schema change so media_arrays_from_tweet_result can no longer find them.","commonSituations":"Queuing arbitrary tweet URLs without checking they contain media; the account posted a poll/text-only reply; Twitter shipped a GraphQL schema change renaming entities fields, breaking extraction for ALL tweets until the parser is updated.","solutions":["Verify the tweet actually contains media before calling the extractor (or accept this as a normal skip result)","Check for a recent Twitter GraphQL schema change and update media_arrays_from_tweet_result field paths","Log the raw tweet_result JSON on failure to confirm which field names are present","Use a pinned, known-good GraphQL operation ID/query hash in case the endpoint changed"],"exampleFix":"// before\nlet media = Self::media_arrays_from_tweet_result(tweet_result)\n    .ok_or_else(|| anyhow!(\"No media found in tweet\"))?;\n// after\nmatch Self::media_arrays_from_tweet_result(tweet_result) {\n    Some(media) if !media.is_empty() => Ok(media),\n    _ => Err(TwitterError::NoMedia { tweet_id }), // lets callers distinguish text-only tweets from schema breakage\n}","handlingStrategy":"validation","validationCode":"// Check the tweet has media before invoking media extraction\nif (!tweet?.extended_entities?.media?.length && !tweet?.entities?.media?.length) {\n  return skip(id, 'text-only tweet');\n}","typeGuard":"function hasExtractableMedia(tweetResult) {\n  return Array.isArray(tweetResult?.legacy?.extended_entities?.media) &&\n         tweetResult.legacy.extended_entities.media.length > 0;\n}","tryCatchPattern":"match tweet.extract_graphql_media(id) {\n    Err(e) if e.to_string() == \"No media found in tweet\" => skip(id, Reason::TextOnly),\n    other => other,\n}","preventionTips":["Filter input URLs/tweet_ids to media-bearing posts when possible","Watch for spikes of this error — they indicate a Twitter GraphQL schema change, not bad data","Pin and periodically verify the GraphQL query hash/operation ID","Log the raw tweet_result JSON when extraction fails to see actual field names"],"tags":["twitter","media","empty-result","schema-change"],"backgroundTag":"empty-result-set","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"}