GuidesIssues Solved

Issues this library solves

react-native-nitro-thumbnail was built knowing the common failure modes of video-thumbnail wrappers. This page maps the real, reported issues against react-native-create-thumbnail to how this library handles each one — most are solved by design (Kotlin + Nitro + the New Architecture), not by patching symptoms.

Issue numbers reference the react-native-create-thumbnail issue tracker.

Android build & compilation

The single largest cluster of reports — all structural, all gone here.

Reported problemIssuesHow nitro-thumbnail avoids it
Unreported exception IOException from retriever.release() on SDK 33+#69, #87, #96, #98Written in Kotlin, which has no checked exceptions — release() in a finally block just compiles.
package org.apache.commons.io … does not exist / missing LastModifiedFileComparator#29, #31No Apache Commons dependency. LRU eviction is a tiny pure-Kotlin helper (filesToEvict), unit-tested.
jcenter / Maven resolution timeouts#78, #68Uses only google() + mavenCentral() — jcenter is dead and never referenced.
AGP 8 / Gradle 9 / RN 0.71+ compatibility#147, #136, #60Fresh New-Architecture scaffold: AGP 8.7.2, Kotlin 2.0.21, Java 17, CMake + prefab.

Remote URLs & network failures

Reported problemIssuesHow nitro-thumbnail handles it
App crashes on a remote video URL (socket / getExceptionHandler)#131, #80Remote setDataSource(url, headers) (Android) and AVURLAsset (iOS) are wrapped — a network failure rejects with a typed REMOTE_FETCH_FAILED, it never crashes the app.
setDataSource failed for YouTube links#62A YouTube page URL isn’t a direct media stream — no library can decode it. We fail cleanly and document that url must point at an actual video file/stream.
Custom auth needed for protected videosFirst-class headers option, forwarded to AVURLAssetHTTPHeaderFieldsKey (iOS) and setDataSource(url, headers) (Android).

UI-thread blocking & performance

Reported problemIssuesHow nitro-thumbnail handles it
Animations stutter / JS frame rate drops while generating#24, #48Every call runs inside Nitro’s Promise.async on a background thread on both platforms. Decoding never touches the UI/JS thread, so batch generation doesn’t jank the UI.
Reported problemIssuesHow nitro-thumbnail handles it
setDataSource failed: status = 0x80000000 for gallery / content:// videos#27content:// URIs are supported on Android — opened via setDataSource(context, uri), the correct path for Storage Access Framework / picker results.
”File doesn’t exist or not supported” for a valid URI#26Clear separation: a missing local file is FILE_NOT_FOUND; an unreadable/undecodable one is DECODE_FAILED.
Thumbnails saved into the device gallery#9Output is written to the app cache directory (cacheDir/thumbnails/), which MediaStore does not scan. No gallery pollution.

iOS-specific

Reported problemIssuesHow nitro-thumbnail handles it
AVFoundationErrorDomain -11832 / -11800 “cannot be used” crashes#56, #117Frame extraction is wrapped; an undecodable asset becomes a typed DECODE_FAILED (or REMOTE_FETCH_FAILED for network) — not an unhandled native error.
Thumbnail returns 0 width / 0 height#7width/height are read from the actual decoded CGImage, so they’re always the real output dimensions.
Wrong orientationappliesPreferredTrackTransform = true honors the video’s rotation metadata, so portrait clips come out upright.

API, modules & ergonomics

Reported problemIssuesHow nitro-thumbnail handles it
null is not an object (CreateThumbnail.create) in Expo#72Nitro autolinks the HybridObject; documented to need an Expo dev build (not Expo Go).
Peer-dependency range too strict#45react and react-native peers are unconstrained (*); only react-native-nitro-modules is pinned.
Configurable JPEG/PNG quality#148First-class quality option (0..1) from day one. See API Reference.
Precise frame time tolerance#142First-class timeToleranceMs option (set 0 for an exact seek).
Opaque Error: null#16Every failure is a typed ThumbnailError with a .code — never a silent null. See Error Handling.

Honest limitations

⚠️

This library is not magic. A few things no thumbnail library can or should do:

  • YouTube / streaming-page URLs (youtube.com/watch?v=…) are not direct media and won’t decode. Pass a real video file or stream URL.
  • iOS Photos ph:// / assets-library:// URIs aren’t opened directly — resolve them to a file:// path first (most image pickers already hand you one). Android content:// is supported.
  • DRM-protected media can’t be decoded by AVFoundation / MediaMetadataRetriever.

When something genuinely can’t be done, you get a typed ThumbnailError — not a crash.

Summary

ThemeStatus
Android build/compile breakage✅ Kotlin + modern AGP, no jcenter, no Apache Commons
Remote-URL crashes✅ Typed REMOTE_FETCH_FAILED, never crashes
UI-thread jank✅ Off-thread via Nitro Promise.async
content:// / gallery videos✅ Supported
Gallery pollution✅ Writes to cache dir only
iOS decode / 0-dimension / orientation✅ Typed errors, real dimensions, correct orientation
Opaque / null errors✅ Typed ThumbnailError.code everywhere

Switching over? See the Migration guide — it’s usually a one-line import change.