{"record":{"id":"72fd0cc146f90684","repo":"immich-app/immich","slug":"failed-to-load-animated-codec-for-asset-key-assetid","errorCode":null,"errorMessage":"Failed to load animated codec for asset ${key.assetId}","messagePattern":"Failed to load animated codec for asset (.+?)","errorType":"exception","errorClass":"StateError","httpStatus":null,"severity":"error","filePath":"mobile/lib/presentation/widgets/images/remote_image_provider.dart","lineNumber":190,"sourceCode":"        edited: key.edited,\n      ),\n    );\n    yield* loadRequest(previewRequest, decode, isFinal: false);\n\n    if (isCancelled) {\n      return;\n    }\n\n    // always try original for animated, since previews don't support animation\n    final originalRequest = request = RemoteImageRequest(\n      uri: getOriginalUrlForRemoteId(key.assetId, edited: key.edited),\n    );\n    final codec = await loadCodecRequest(originalRequest, isFinal: true);\n    if (codec == null) {\n      if (isCancelled) {\n        return;\n      }\n      throw StateError('Failed to load animated codec for asset ${key.assetId}');\n    }\n    yield codec;\n  }\n\n  @override\n  bool operator ==(Object other) {\n    if (identical(this, other)) {\n      return true;\n    }\n    if (other is RemoteFullImageProvider) {\n      return assetId == other.assetId &&\n          thumbhash == other.thumbhash &&\n          isAnimated == other.isAnimated &&\n          edited == other.edited;\n    }\n\n    return false;\n  }","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/mobile/lib/presentation/widgets/images/remote_image_provider.dart#L172-L208","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nif (codec == null) {\n  throw StateError('Failed to load animated codec for asset ${key.assetId}');\n}\n// after\nif (codec == null) {\n  if (isCancelled) return;\n  yield* _fallbackStaticImage(originalRequest); // or emit error state to widget\n  return;\n}","handlingStrategy":"try-catch","validationCode":"// before building the provider\nfinal exists = await api.asset.getAssetInfo(key.assetId);\nif (!exists.isAnimated) return StaticImageProvider(key);","typeGuard":"bool isCodecAvailable(CodecRequest req) => codecRegistry.contains(req.mimeType);","tryCatchPattern":"try {\n  await for (final frame in provider.stream) render(frame);\n} on StateError catch (e) {\n  if (e.message.contains('animated codec')) showStaticFallback(key.assetId);\n  rethrow;\n}","preventionTips":["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"],"tags":["flutter","image-decoding","codec","asset-loading"],"backgroundTag":"resource-not-found","analyzedSha":"e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}