| "Failed once, now fails instantly for ~a minute" | Negative cache memoizes non-cancellation failures for negativeCacheTtl (default 60s) and replays the original exception | For explicit retry buttons / connectivity-restored: await engine.evict(source) then re-request. Globally: shorter negativeCacheTtl in configure (re-running configure also clears all failure memos) |
"404 URL reports timeout not network on Android" | Some Android media stacks retry internally and never surface HTTP status; the Dart deadline ends the attempt | Documented platform quirk. Bucket timeout+network together for remote-source analytics; optionally probe the URL app-side to reclassify |
| "Cache stopped working / thumbnails regenerate after days" | Cache lives in the OS-purgeable app cache dir; the OS reclaimed it | By design; engine re-extracts on demand. Do not move the cache; reduce churn with correct shared specs |
| "Changed request headers but same thumbnail" | Headers are deliberately excluded from cache identity | evict(source) when content truly changed |
| "Thumbnail is not the exact frame I asked for" | exact: false snaps to nearest keyframe (the fast path) | exact: true only where precision matters; never in feeds |
| "First frame is black" | Many videos open on black; position 0 + keyframe snap lands there | position: Duration(seconds: 1) (still keyframe-fast) |
| "HLS (.m3u8) works on one platform, fails on other" | Stream thumbnailing depends on OS media stack support; both outcomes are classified, bounded failures | Treat HLS tiles as best-effort with an error placeholder, or use direct MP4 URLs |
| "Cancelled request still produced a cache file (Android)" | Android cannot abort MediaMetadataRetriever; the engine detaches the caller and banks the finished frame | By design (sunk cost -> future hit). iOS aborts natively |
| "Portrait video renders sideways/wrong box" | Rotation metadata is applied natively; fit box is display-oriented | Expected correct; if actually sideways, that IS a defect - report upstream with the file |
| "StateError: cache sizing can only be configured before the first request" | maxCacheBytes/maxCacheEntries are locked once the engine initializes | Move the single configure() call to main() before any request |
| "evict/clearCache didn't cancel a running extraction" | Eviction only removes stored entries; in-flight work completes | Cancel via the request handle; or ignore - next request re-checks cache |