{"record":{"id":"b52566ca3de48b8f","repo":"immich-app/immich","slug":"unable-to-find-existing-motion-video-asset-for-asset-id","errorCode":null,"errorMessage":"Unable to find existing motion video asset for ${asset.id}: ${asset.originalPath}","messagePattern":"Unable to find existing motion video asset for (.+?): (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/src/services/metadata.service.ts","lineNumber":753,"sourceCode":"            ownerId: asset.ownerId,\n            originalPath: StorageCore.getAndroidMotionPath(asset, motionAssetId),\n            originalFileName: `${parse(asset.originalFileName).name}.mp4`,\n            visibility: AssetVisibility.Hidden,\n          });\n\n          isNewMotionAsset = true;\n\n          if (!asset.isExternal) {\n            await this.userRepository.updateUsage(asset.ownerId, video.byteLength);\n          }\n        } catch (error) {\n          if (!isAssetChecksumConstraint(error)) {\n            throw error;\n          }\n\n          motionAsset = await this.assetRepository.getByChecksum(checksumQuery);\n          if (!motionAsset) {\n            this.logger.warn(`Unable to find existing motion video asset for ${asset.id}: ${asset.originalPath}`);\n            return;\n          }\n        }\n      }\n\n      if (!isNewMotionAsset) {\n        this.logger.debugFn(() => {\n          const base64Checksum = checksum.toString('base64');\n          return `Motion asset with checksum ${base64Checksum} already exists for asset ${asset.id}: ${asset.originalPath}`;\n        });\n      }\n\n      // Hide the motion photo video asset if it's not already hidden to prepare for linking\n      if (motionAsset.visibility === AssetVisibility.Timeline) {\n        await this.assetRepository.update({\n          id: motionAsset.id,\n          visibility: AssetVisibility.Hidden,\n        });","sourceCodeStart":735,"sourceCodeEnd":771,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/services/metadata.service.ts#L735-L771","documentation":"This is a warning (not a throw) logged by applyMotionPhotos when, after a checksum conflict was detected and re-lookup was attempted, no existing motion video asset can be found for the photo asset. Motion photo handling (Apple Live Photo / Samsung Motion Photo) expects a paired video asset to already exist or be creatable; if the checksum-based lookup returns nothing, the pairing is abandoned for that asset and the job returns early. The photo is left unpaired with its motion video.","triggerScenarios":"Job handleMetadataExtraction processes an asset whose metadata indicates a motion photo; the initial insert of the motion asset hits a unique checksum constraint error, so the code re-queries assetRepository.getByChecksum(checksumQuery), and that query returns null (the conflicting asset is not visible or was concurrently deleted).","commonSituations":"Concurrent metadata-extraction jobs racing on the same motion video file; a checksum-constraint error caused by an asset in a state that the follow-up query does not match (e.g. different library/visibility scope in the query); orphaned or deleted motion assets after partial cleanup; libraries re-scanned with changed storage layout.","solutions":["Re-run the metadata extraction job for the affected asset — the race is often transient and a second pass will find or create the motion asset.","Verify the motion video file still exists on disk at the path derived from the photo's sidecar/adjacent file and that its checksum matches what was queried.","Check for and delete orphaned/partially-created asset rows (asset with the checksum missing or in a conflicting library) via the database or admin tooling.","Ensure only one server instance / one library-scan worker processes the same library at a time to avoid insert races."],"exampleFix":"// before\nmotionAsset = await this.assetRepository.getByChecksum(checksumQuery);\nif (!motionAsset) {\n  this.logger.warn(`Unable to find existing motion video asset for ${asset.id}: ${asset.originalPath}`);\n  return;\n}\n// after\nmotionAsset = await this.assetRepository.getByChecksum(checksumQuery);\nif (!motionAsset) {\n  this.logger.warn(`Unable to find existing motion video asset for ${asset.id}: ${asset.originalPath}; retrying lookup without library scope`);\n  motionAsset = await this.assetRepository.getByChecksum({ checksum });\n  if (!motionAsset) return;\n}","handlingStrategy":"fallback","validationCode":"// before enqueuing extraction, verify the motion video file exists\nconst motionPath = getMotionVideoPath(asset.originalPath);\nif (!motionPath || !fs.existsSync(motionPath)) {\n  this.logger.warn(`Skipping motion pairing: missing motion video for ${asset.id}`);\n  return JobStatus.Skipped;\n}","typeGuard":"const isAsset = (a: AssetResponse | null | undefined): a is AssetResponse =>\n  !!a && typeof a.id === 'string' && typeof a.checksum === 'string';","tryCatchPattern":"try {\n  await this.applyMotionPhotos(asset, exifData);\n} catch (error) {\n  this.logger.warn(`Motion photo pairing failed for ${asset.id}: ${error}`);\n  return JobStatus.Failed;\n}","preventionTips":["Avoid running multiple extraction workers over the same library concurrently to prevent checksum insert races.","After any bulk delete or library re-scan, re-run metadata extraction so pairings are rebuilt.","Monitor for 'Unable to find existing motion video asset' warnings and reconcile orphaned assets periodically.","Keep motion-video sidecar files together with their photos when moving or syncing libraries."],"tags":["immich","motion-photo","checksum","race-condition","metadata-extraction"],"backgroundTag":"record-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"}