immich-app/immich · error · StateError
Failed to load animated codec for asset
Error message
Failed to load animated codec for asset ${key.assetId} What it means
The remote image provider attempted to decode an animated asset (e.g. a Live Photo or animated image) but the codec loader returned null even though the request was not cancelled. The provider throws a StateError because it cannot produce any frames to yield. It indicates a decode/codec-loading failure for that specific asset.
Solutions
- Verify a codec factory is registered for the asset's format before the provider is used
- Check the asset still exists and is downloadable from the server (hit its URL directly)
- Log inside loadCodecRequest to find why it returns null (network, decode, or registration)
- Handle null gracefully in the UI by falling back to a static thumbnail instead of throwing
Example fix
// before
if (codec == null) {
throw StateError('Failed to load animated codec for asset ${key.assetId}');
}
// after
if (codec == null) {
if (isCancelled) return;
yield* _fallbackStaticImage(originalRequest); // or emit error state to widget
return;
} Defensive patterns
Strategy: try-catch
Validate before calling
// before building the provider final exists = await api.asset.getAssetInfo(key.assetId); if (!exists.isAnimated) return StaticImageProvider(key);
Type guard
bool isCodecAvailable(CodecRequest req) => codecRegistry.contains(req.mimeType);
Try / catch
try {
await for (final frame in provider.stream) render(frame);
} on StateError catch (e) {
if (e.message.contains('animated codec')) showStaticFallback(key.assetId);
rethrow;
} Prevention
- Register codec factories for all supported animated formats at app startup
- Fall back to a static thumbnail when animated decoding fails
- Check asset availability before constructing the provider
When it happens
Trigger: loadCodecRequest(originalRequest, isFinal: true) resolves to null while isCancelled is false — e.g. the asset bytes failed to fetch or decode, the codec factory was never registered for the asset's format, or the asset was deleted/changed server-side between request and load.
Common situations: Viewing a Motion Photo / Live Photo whose video or image component is unavailable; a custom codec plugin not registered; stale asset references after server migration; network failure on the final chunk of the asset download.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Codec ' ' does not support HLS codec strings
- Codec ' ' is unsupported
- acceleration does not support codec ' '. Supported codecs
- Failed to load animated codec for local asset
- Invalid image data
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/72fd0cc146f90684.
Report an issue: GitHub.
Appendix: source
Thrown at mobile/lib/presentation/widgets/images/remote_image_provider.dart:190
edited: key.edited,
),
);
yield* loadRequest(previewRequest, decode, isFinal: false);
if (isCancelled) {
return;
}
// always try original for animated, since previews don't support animation
final originalRequest = request = RemoteImageRequest(
uri: getOriginalUrlForRemoteId(key.assetId, edited: key.edited),
);
final codec = await loadCodecRequest(originalRequest, isFinal: true);
if (codec == null) {
if (isCancelled) {
return;
}
throw StateError('Failed to load animated codec for asset ${key.assetId}');
}
yield codec;
}
@override
bool operator ==(Object other) {
if (identical(this, other)) {
return true;
}
if (other is RemoteFullImageProvider) {
return assetId == other.assetId &&
thumbhash == other.thumbhash &&
isAnimated == other.isAnimated &&
edited == other.edited;
}
return false;
}View on GitHub (pinned to e55ac299a4)