{"record":{"id":"c461e7ff7cb43b1b","repo":"immich-app/immich","slug":"live-photo-video-does-not-belong-to-the-user","errorCode":null,"errorMessage":"Live photo video does not belong to the user","messagePattern":"Live photo video does not belong to the user","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"server/src/utils/asset.util.ts","lineNumber":157,"sourceCode":"\n  return [...partnerIds];\n};\n\nexport type AssetHookRepositories = { asset: AssetRepository; event: EventRepository };\n\nexport const onBeforeLink = async (\n  { asset: assetRepository, event: eventRepository }: AssetHookRepositories,\n  { userId, livePhotoVideoId }: { userId: string; livePhotoVideoId: string },\n) => {\n  const motionAsset = await assetRepository.getById(livePhotoVideoId);\n  if (!motionAsset) {\n    throw new BadRequestException('Live photo video not found');\n  }\n  if (motionAsset.type !== AssetType.Video) {\n    throw new BadRequestException('Live photo video must be a video');\n  }\n  if (motionAsset.ownerId !== userId) {\n    throw new BadRequestException('Live photo video does not belong to the user');\n  }\n\n  if (motionAsset && motionAsset.visibility === AssetVisibility.Timeline) {\n    await assetRepository.update({ id: livePhotoVideoId, visibility: AssetVisibility.Hidden });\n    await eventRepository.emit('AssetHide', { assetId: motionAsset.id, userId });\n  }\n};\n\nexport const onBeforeUnlink = async (\n  { asset: assetRepository }: AssetHookRepositories,\n  { livePhotoVideoId }: { livePhotoVideoId: string },\n) => {\n  const motion = await assetRepository.getById(livePhotoVideoId);\n  if (!motion) {\n    return null;\n  }\n\n  if (StorageCore.isAndroidMotionPath(motion.originalPath)) {","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/utils/asset.util.ts#L139-L175","documentation":"Thrown by onBeforeLink when the motion video asset exists and is a video, but its ownerId differs from the userId performing the link. Users may only attach live photo motion videos they own; this enforces per-user asset ownership.","triggerScenarios":"A user attempts to link a motion video uploaded by another user (e.g. shared asset), or an admin job runs with a mismatched user context.","commonSituations":"Using a shared album partner's video as your photo's motion component; automation scripts that mix up user credentials; duplicated users after account merge.","solutions":["Ensure the motion video is uploaded by the same user performing the link","Log in as the owner user or run the operation with the owner's credentials","Copy/upload the motion video under the correct user account before linking","If legitimate sharing is needed, use the official share flow rather than direct linking"],"exampleFix":"// before\nawait onBeforeLink(repos, { userId: me.id, livePhotoVideoId: partnersVideoId });\n// after\nconst motion = await assetRepository.getById(partnersVideoId);\nif (motion && motion.ownerId === me.id) {\n  await onBeforeLink(repos, { userId: me.id, livePhotoVideoId: partnersVideoId });\n} else {\n  throw new Error('Motion video must be owned by the linking user');\n}","handlingStrategy":"validation","validationCode":"if (motionAsset.ownerId !== currentUserId) {\n  throw new Error('Motion video must be owned by the linking user');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await linkLivePhoto(assetId, livePhotoVideoId);\n} catch (e) {\n  if (e.status === 400 && /does not belong/.test(e.message)) {\n    // re-upload the video under the current user and retry\n  }\n}","preventionTips":["Authenticate as the owner user when running bulk live photo jobs","Never mix credentials across users in automation scripts","Compare ownerId on both assets before linking"],"tags":["asset","ownership","authorization"],"backgroundTag":"permission-denied","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"}