immich-app/immich · error · BadRequestException

Cannot unlink Android motion photos

Error message

Cannot unlink Android motion photos

What it means

Thrown by onBeforeUnlink when attempting to unlink a live photo motion video that lives at an Android motion photo path. Android motion photos embed the video inside the photo's storage layout, so unlinking would corrupt the paired file; Immich blocks it.

Solutions

  1. Skip unlinking for assets whose originalPath matches an Android motion path
  2. Use the Android motion photo removal workflow (reprocess the asset without motion extraction) instead of unlink
  3. Only unlink motion videos that were uploaded as separate iOS-style live photo videos

Example fix

// before
await onBeforeUnlink(repos, { livePhotoVideoId: motion.id });
// after
if (StorageCore.isAndroidMotionPath(motion.originalPath)) {
  console.warn(`Skip unlink: ${motion.id} is an Android motion photo`);
} else {
  await onBeforeUnlink(repos, { livePhotoVideoId: motion.id });
}
Defensive patterns

Strategy: validation

Validate before calling

if (motion.originalPath && /MotionPhoto|motionphoto|EmbeddedVideo/i.test(motion.originalPath)) {
  // treat as Android motion photo; skip unlink
}

Try / catch

try {
  await unlinkLivePhoto(livePhotoVideoId);
} catch (e) {
  if (e.status === 400 && /Android motion/.test(e.message)) {
    // use the motion-photo removal/reprocess workflow instead
  }
}

Prevention

When it happens

Trigger: Calling onBeforeUnlink on a motion video whose originalPath matches StorageCore.isAndroidMotionPath, i.e. the video was extracted from / belongs to an Android motion photo.

Common situations: Bulk unlink scripts processing all live photo videos indiscriminately; users trying to detach motion from an Android-captured photo; migration or dedup jobs touching Android motion pairs.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at server/src/utils/asset.util.ts:176

  }

  if (motionAsset && motionAsset.visibility === AssetVisibility.Timeline) {
    await assetRepository.update({ id: livePhotoVideoId, visibility: AssetVisibility.Hidden });
    await eventRepository.emit('AssetHide', { assetId: motionAsset.id, userId });
  }
};

export const onBeforeUnlink = async (
  { asset: assetRepository }: AssetHookRepositories,
  { livePhotoVideoId }: { livePhotoVideoId: string },
) => {
  const motion = await assetRepository.getById(livePhotoVideoId);
  if (!motion) {
    return null;
  }

  if (StorageCore.isAndroidMotionPath(motion.originalPath)) {
    throw new BadRequestException('Cannot unlink Android motion photos');
  }

  return motion;
};

export const onAfterUnlink = async (
  { asset: assetRepository, event: eventRepository }: AssetHookRepositories,
  { userId, livePhotoVideoId, visibility }: { userId: string; livePhotoVideoId: string; visibility: AssetVisibility },
) => {
  await assetRepository.update({ id: livePhotoVideoId, visibility });
  await eventRepository.emit('AssetShow', { assetId: livePhotoVideoId, userId });
};

export function mapToUploadFile(file: ImmichFile): UploadFile {
  return {
    uuid: file.uuid,
    checksum: file.checksum,
    originalPath: file.path,

View on GitHub (pinned to e55ac299a4)