immich-app/immich · error · IOException
Could not read image data for $assetId
Error message
Could not read image data for $assetId
What it means
getEncodedImageInternal in LocalImagesImpl.kt opens a MediaStore content InputStream for the given asset ID and reads all bytes. If openInputStream returns null (the provider cannot open the URI) it throws IOException 'Could not read image data for $assetId', which propagates to the Flutter side as a load failure for that thumbnail.
Solutions
- Re-query MediaStore for the asset ID; treat this asset as stale and remove it from the local listing.
- Verify storage/photo permissions (READ_MEDIA_IMAGES / READ_EXTERNAL_STORAGE) are granted.
- Check the file is not a cloud-only placeholder — trigger download or skip until available.
- Re-run a full media sync so deleted assets are pruned before requesting thumbnails.
Example fix
// before
final bytes = await LocalImagesApi.getEncodedImage(assetId);
// after
try {
bytes = await LocalImagesApi.getEncodedImage(assetId);
} catch (e) {
await removeFromLocalIndex(assetId); // stale MediaStore entry
} Defensive patterns
Strategy: try-catch
Validate before calling
// Dart: confirm asset still exists locally before requesting bytes final exists = await localApi.assetExists(assetId); // re-query MediaStore
Try / catch
try {
bytes = await api.getEncodedImage(assetId);
} catch (e) {
markAssetMissing(assetId); // prune stale entry, continue sync
} Prevention
- Prune deleted assets from the local index before thumbnailing.
- Verify READ_MEDIA_IMAGES permission at runtime.
- Skip cloud-placeholder assets until downloaded.
When it happens
Trigger: The asset ID no longer exists in MediaStore (deleted or moved), the URI is unresolvable, or the content provider denies the stream for a cloud-backed/offline item.
Common situations: Thumbnailing assets that were deleted on the device since the last sync; backups restored to a device where local files are cloud placeholders; missing READ_MEDIA_IMAGES permission on newer Android versions.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Cannot open original stream for asset $assetId
- could not convert bitmap to ARGB_8888
- native rotate failed for orientation $orientation
- Cannot unlink Android motion photos
- EOFException
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/7b58f423a37772cd.
Report an issue: GitHub.
Appendix: source
Thrown at mobile/android/app/src/main/kotlin/app/alextran/immich/images/LocalImagesImpl.kt:190
request.callback(CANCELLED)
} catch (_: Exception) {
}
}
}
}
private fun getEncodedImageInternal(
assetId: String,
callback: (Result<Map<String, Long>?>) -> Unit,
signal: CancellationSignal
) {
signal.throwIfCanceled()
val id = assetId.toLong()
val uri = ContentUris.withAppendedId(Images.Media.EXTERNAL_CONTENT_URI, id)
signal.throwIfCanceled()
val bytes = resolver.openInputStream(uri)?.use { it.readBytes() }
?: throw IOException("Could not read image data for $assetId")
signal.throwIfCanceled()
val pointer = NativeBuffer.allocate(bytes.size)
try {
val buffer = NativeBuffer.wrap(pointer, bytes.size)
buffer.put(bytes)
signal.throwIfCanceled()
callback(Result.success(mapOf(
"pointer" to pointer,
"length" to bytes.size.toLong()
)))
} catch (e: Exception) {
NativeBuffer.free(pointer)
throw e
}
}
private fun getThumbnailBufferInternal(View on GitHub (pinned to e55ac299a4)