tonhowtf/omniget · warning
[omnidisc] unwatch failed
Error message
[omnidisc] unwatch failed
What it means
unwatchStream invokes `omnidisc_stream_unwatch` to stop receiving a user's stream. On backend rejection the warning is logged, but the finally block always removes the userId from `watchingIds`, so local state and backend state can diverge. Called from initStream, toggleWatch, and stop (which unwatch all ids during teardown).
Solutions
- Make the backend unwatch idempotent (no-op + Ok when the id is unknown).
- Filter the id from watchingIds before invoking, or reconcile backend watch state via a stats/refresh call after failure.
- Log errorText(e) server-side correlation: inspect the Rust error to see if it is 'not watching' vs command-missing.
- Deduplicate toggleWatch so unwatch is not issued twice concurrently.
Example fix
// before
await invoke("omnidisc_stream_unwatch", { userId });
// after
if (watchingIds.includes(userId)) {
await invoke("omnidisc_stream_unwatch", { userId });
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!watchingIds.includes(userId)) return;
Try / catch
try {
await invoke("omnidisc_stream_unwatch", { userId });
} catch (e) {
console.warn("[omnidisc] unwatch failed", errorText(e));
} finally {
watchingIds = watchingIds.filter((id) => id !== userId);
} Prevention
- Keep local watchingIds and backend watch state reconciled via periodic stats refresh.
- Make backend unwatch a no-op for unknown ids.
- Avoid issuing unwatch while a watch for the same id is still in flight.
- Deduplicate teardown loops (stop() unwatching ids already being unwatched).
When it happens
Trigger: Calling unwatchStream(userId) for a userId the backend is not watching, a malformed userId, or when the backend `omnidisc_stream_unwatch` command panics/is unregistered. Also fires during stop() teardown for every watched id.
Common situations: Backend already dropped the peer (stream ended server-side) so unwatch finds nothing; duplicate unwatch after a toggle race; stale watch entries after a reconnect.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
- [omnidisc] stop stream failed
- e.to_string()
- [omnidisc] media capabilities unavailable
- [omnidisc] stream volume failed
- [omnidisc] stream events subscribe failed
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/a513e80982d4c866.
Report an issue: GitHub.
Appendix: source
Thrown at src/lib/stores/omnidisc-stream-store.svelte.ts:289
busy = true;
lastError = null;
try {
await invoke("omnidisc_stream_watch", { userId });
if (!watchingIds.includes(userId)) watchingIds = [...watchingIds, userId];
return true;
} catch (e) {
lastError = errorText(e);
return false;
} finally {
busy = false;
}
}
export async function unwatchStream(userId: string): Promise<void> {
try {
await invoke("omnidisc_stream_unwatch", { userId });
} catch (e) {
console.warn("[omnidisc] unwatch failed", errorText(e));
} finally {
watchingIds = watchingIds.filter((id) => id !== userId);
}
}
export async function setStreamVolume(userId: string, gain: number): Promise<void> {
try {
await invoke("omnidisc_stream_set_volume", { userId, gain: Math.min(2, Math.max(0, gain)) });
} catch (e) {
console.warn("[omnidisc] stream volume failed", errorText(e));
}
}
export async function refreshStreamStats(): Promise<StreamStats | null> {
try {
stats = await invoke<StreamStats>("omnidisc_stream_stats");
if (stats.publishing) publishing = stats.publishing;
return stats;View on GitHub (pinned to 8600b91f42)