immich-app/immich · warning

Unable to find existing motion video asset for

Error message

Unable to find existing motion video asset for ${asset.id}: ${asset.originalPath}

What it means

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.

Solutions

  1. 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.
  2. 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.
  3. 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.
  4. Ensure only one server instance / one library-scan worker processes the same library at a time to avoid insert races.

Example fix

// before
motionAsset = await this.assetRepository.getByChecksum(checksumQuery);
if (!motionAsset) {
  this.logger.warn(`Unable to find existing motion video asset for ${asset.id}: ${asset.originalPath}`);
  return;
}
// after
motionAsset = await this.assetRepository.getByChecksum(checksumQuery);
if (!motionAsset) {
  this.logger.warn(`Unable to find existing motion video asset for ${asset.id}: ${asset.originalPath}; retrying lookup without library scope`);
  motionAsset = await this.assetRepository.getByChecksum({ checksum });
  if (!motionAsset) return;
}
Defensive patterns

Strategy: fallback

Validate before calling

// before enqueuing extraction, verify the motion video file exists
const motionPath = getMotionVideoPath(asset.originalPath);
if (!motionPath || !fs.existsSync(motionPath)) {
  this.logger.warn(`Skipping motion pairing: missing motion video for ${asset.id}`);
  return JobStatus.Skipped;
}

Type guard

const isAsset = (a: AssetResponse | null | undefined): a is AssetResponse =>
  !!a && typeof a.id === 'string' && typeof a.checksum === 'string';

Try / catch

try {
  await this.applyMotionPhotos(asset, exifData);
} catch (error) {
  this.logger.warn(`Motion photo pairing failed for ${asset.id}: ${error}`);
  return JobStatus.Failed;
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15). Data as JSON: /api/errors/b52566ca3de48b8f. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/metadata.service.ts:753

            ownerId: asset.ownerId,
            originalPath: StorageCore.getAndroidMotionPath(asset, motionAssetId),
            originalFileName: `${parse(asset.originalFileName).name}.mp4`,
            visibility: AssetVisibility.Hidden,
          });

          isNewMotionAsset = true;

          if (!asset.isExternal) {
            await this.userRepository.updateUsage(asset.ownerId, video.byteLength);
          }
        } catch (error) {
          if (!isAssetChecksumConstraint(error)) {
            throw error;
          }

          motionAsset = await this.assetRepository.getByChecksum(checksumQuery);
          if (!motionAsset) {
            this.logger.warn(`Unable to find existing motion video asset for ${asset.id}: ${asset.originalPath}`);
            return;
          }
        }
      }

      if (!isNewMotionAsset) {
        this.logger.debugFn(() => {
          const base64Checksum = checksum.toString('base64');
          return `Motion asset with checksum ${base64Checksum} already exists for asset ${asset.id}: ${asset.originalPath}`;
        });
      }

      // Hide the motion photo video asset if it's not already hidden to prepare for linking
      if (motionAsset.visibility === AssetVisibility.Timeline) {
        await this.assetRepository.update({
          id: motionAsset.id,
          visibility: AssetVisibility.Hidden,
        });

View on GitHub (pinned to e55ac299a4)