tonhowtf/omniget · warning

[TG] loadMedia failed in ${(performance.now() - t0).toFixed(

Error message

[TG] loadMedia failed in ${(performance.now() - t0).toFixed(0)}ms:

What it means

loadMedia() in TelegramBrowser.svelte fetches media items with a Promise.race against a timeout promise; on failure the catch logs '[TG] loadMedia failed in Nms:' with the error message and sets mediaError. The rejection comes either from the underlying fetch/IPC (TDPF/telegram media listing) or from the injected timeout promise, and the elapsed time is logged to help distinguish slow-but-successful calls from hard failures.

Solutions

  1. Check the logged message and elapsed ms: near-zero ms means an immediate rejection (service/session issue); near the timeout value means a slow fetch.
  2. Raise the timeout constant or increase PAGE_SIZE tuning if large pages legitimately exceed the deadline.
  3. Verify the Telegram session/authorization is valid and the media backend service is reachable.
  4. Add retry with exponential backoff for transient network failures before surfacing mediaError.
  5. Ensure loadMedia is not re-entered while mediaLoading is true (concurrent calls can race and thrash).

Example fix

// before
const items = await Promise.race([fetchPromise, timeoutPromise]);
// after
let attempt = 0;
const items = await (async () => {
  while (attempt < 3) {
    try {
      return await Promise.race([fetchPromise, timeoutPromise]);
    } catch (e) {
      if (++attempt >= 3) throw e;
      await new Promise((r) => setTimeout(r, 500 * attempt));
    }
  }
})();
Defensive patterns

Strategy: retry

Validate before calling

// before calling loadMedia
if (mediaLoading) return; // prevent concurrent overlapping fetches
if (!telegramSessionValid) { mediaError = 'Session expired'; return; }

Type guard

function isTimeoutError(e: unknown, elapsedMs: number, budgetMs: number): boolean {
  if (!(e instanceof Error)) return String(e).includes('timeout');
  return elapsedMs >= budgetMs - 50;
}

Try / catch

try {
  await loadMedia(reset);
} catch (e) {
  const msg = e instanceof Error ? e.message : String(e);
  if (msg.includes('timeout')) {
    await retryWithBackoff(() => loadMedia(reset), 3);
  } else {
    mediaError = msg;
  }
}

Prevention

When it happens

Trigger: The media fetch promise rejects (backend/IPC error while listing Telegram media) OR the timeout promise fires first because fetching exceeded the configured deadline; the resulting message is then stored in mediaError and rendered in the component.

Common situations: Slow Telegram API/media backend exceeding the page-load timeout on large galleries; network drop or paused backend while scrolling an infinite list; expired Telegram session/authorization causing the media query to reject; media service not running so the invoke fails immediately.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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

Appendix: source

Thrown at src/lib/study-components/TelegramBrowser.svelte:1560

        offset: reset ? 0 : mediaItems.length,
        limit: PAGE_SIZE,
      };
      if (mediaFilter !== "all") args.mediaType = mediaFilter;
      const fetchPromise = telegramListMedia(args);
      const timeoutMs = 25_000;
      const timeoutPromise = new Promise<TelegramMediaItem[]>((_, reject) =>
        setTimeout(
          () => reject(new Error(`telegram_list_media timeout (${timeoutMs}ms) — provavelmente FLOOD_WAIT, tente novamente em alguns segundos`)),
          timeoutMs,
        ),
      );
      const items = await Promise.race([fetchPromise, timeoutPromise]);
      console.log(`[TG] loadMedia ok in ${(performance.now() - t0).toFixed(0)}ms, returned ${items.length} items`);
      mediaItems = reset ? items : [...mediaItems, ...items];
      mediaHasMore = items.length >= PAGE_SIZE;
    } catch (e) {
      const msg = e instanceof Error ? e.message : String(e);
      console.warn(`[TG] loadMedia failed in ${(performance.now() - t0).toFixed(0)}ms:`, msg);
      mediaError = msg;
    } finally {
      mediaLoading = false;
    }
  }

  // F0.1 + F0.2: throttle + raf-batch for media thumbs
  const thumbFetchLimit = makeLimit(4);
  const pendingThumbUpdates = new Map<number, string>();
  let thumbFlushScheduled = false;
  function flushThumbUpdates() {
    thumbFlushScheduled = false;
    if (pendingThumbUpdates.size === 0) return;
    const next = new Map(mediaThumbs);
    for (const [k, v] of pendingThumbUpdates) next.set(k, v);
    pendingThumbUpdates.clear();
    mediaThumbs = next;
  }

View on GitHub (pinned to 8600b91f42)