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
- Read the logged `err` to see whether it's a command failure or 'no audio format returned'.
- Retry the primary command once — transient YouTube API failures are common.
- Confirm the backend's yt-dlp is up to date, since the legacy path is the only one that works when the primary fails.
- 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
- Keep yt-dlp updated in the backend since it's the fallback path.
- Add a single retry for the primary resolver before falling back.
- Log which resolver served each track for easier triage.
- Monitor fallback frequency as a health signal for the primary pipeline.
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
- read timed out after
- stream error
- [study-music] sponsorblock lookup failed:
- [study-music] yt refresh failed
- /
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)