tonhowtf/omniget · warning

[study-music] study:youtube:player failed, falling back to…

Error message

[study-music] study:youtube:player failed, falling back to yt-dlp resolver:

What it means

The player's preferred YouTube pipeline (study:youtube:player, returning audio+video formats and chapters) failed, and the store deliberately falls back to the legacy yt-dlp resolver (study:music:youtube:track_stream_url). This warn is the diagnostic breadcrumb for that fallback path, not a playback failure — playback continues via the legacy resolver.

Solutions

  1. Read the logged `err` to see whether it's a command failure or 'no audio format returned'.
  2. Retry the primary command once — transient YouTube API failures are common.
  3. Confirm the backend's yt-dlp is up to date, since the legacy path is the only one that works when the primary fails.
  4. If primary failures are persistent, check backend network egress/YouTube client config for the study:youtube:player resolver.
Defensive patterns

Strategy: fallback

Validate before calling

// pre-check resolver availability
const hasPlayer = await pluginInvoke<boolean>("study", "study:music:has_youtube_player").catch(() => false);

Type guard

function hasAudioFormat(res: unknown): res is { audio: { url: string }; video?: unknown; chapters?: unknown[] } {
  return typeof res === "object" && res !== null && "audio" in res;
}

Try / catch

try {
  const res = await pluginInvoke("study", "study:youtube:player", { videoId });
  if (!res?.audio) throw new Error("no audio format returned");
} catch (err) {
  console.warn("[study-music] primary resolver failed, falling back:", err);
  const legacy = await pluginInvoke("study", "study:music:youtube:track_stream_url", { videoId });
}

Prevention

When it happens

Trigger: pluginInvoke('study','study:youtube:player',{videoId}) rejecting or returning no audio format ('no audio format returned') while resolving a YouTube track; then the legacy track_stream_url call is attempted.

Common situations: Backend resolver can't find a suitable audio itag; YouTube throttles or blocks the primary API; expiry/degradation of the player endpoint; age/region-restricted videos returning empty format lists; backend yt-dlp-only build lacking the primary player command.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/e75c630f363dce62. Report an issue: GitHub.

Appendix: source

Thrown at src/lib/study-music/player-store.svelte.ts:1607

  private async resolveYoutubeMedia(
    videoId: string,
  ): Promise<{ audio: string | null; video: string | null; legacy: boolean }> {
    try {
      const { studyYoutubePlayer } = await import("$lib/study-bridge");
      const res = await studyYoutubePlayer({ videoId });
      if (res.sabr_only) {
        throw new Error(
          "SABR-only stream: no directly playable format (format unavailable in this client yet)",
        );
      }
      const audio = pickBestYoutubeAudio(res);
      const video = pickBestYoutubeVideo(res);
      if (!audio) throw new Error("no audio format returned");
      this.youtubeChapters = res.chapters ?? [];
      this.scheduleYoutubeRefresh(videoId, res.expires_at);
      return { audio, video, legacy: false };
    } catch (err) {
      console.warn(
        "[study-music] study:youtube:player failed, falling back to yt-dlp resolver:",
        err,
      );
      const legacy = await pluginInvoke<{ url: string; via?: string }>(
        "study",
        "study:music:youtube:track_stream_url",
        { video_id: videoId },
      );
      if (!legacy.url) {
        throw err instanceof Error
          ? err
          : new Error(typeof err === "string" ? err : "youtube resolve failed");
      }
      this.youtubeChapters = [];
      return { audio: legacy.url, video: null, legacy: true };
    }
  }

View on GitHub (pinned to 8600b91f42)