immich-app/immich · error · BadRequestException
Live photo video not found
Error message
Live photo video not found
What it means
Thrown by onBeforeLink in server/src/utils/asset.util.ts when a user attempts to link a Live Photo's still image to a motion video asset, but no asset exists in the database for the supplied livePhotoVideoId. It is a NestJS BadRequestException (HTTP 400), surfaced through asset update calls. The lookup is done via assetRepository.getById(livePhotoVideoId).
Source
Thrown at server/src/utils/asset.util.ts:151
if (timelineEnabled && !partner.inTimeline) {
continue;
}
partnerIds.add(partner.sharedById);
}
return [...partnerIds];
};
export type AssetHookRepositories = { asset: AssetRepository; event: EventRepository };
export const onBeforeLink = async (
{ asset: assetRepository, event: eventRepository }: AssetHookRepositories,
{ userId, livePhotoVideoId }: { userId: string; livePhotoVideoId: string },
) => {
const motionAsset = await assetRepository.getById(livePhotoVideoId);
if (!motionAsset) {
throw new BadRequestException('Live photo video not found');
}
if (motionAsset.type !== AssetType.Video) {
throw new BadRequestException('Live photo video must be a video');
}
if (motionAsset.ownerId !== userId) {
throw new BadRequestException('Live photo video does not belong to the user');
}
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 },
) => {View on GitHub (pinned to 199723261c)
Solutions
- Verify the motion video asset was uploaded successfully and capture its real id before linking it as livePhotoVideoId.
- Confirm livePhotoVideoId belongs to the same user and still exists (e.g. GET /assets/:id) before submitting the link request.
- If the asset was deleted, re-upload the motion video and use the new id.
Example fix
// before
await updateAsset({ id, livePhotoVideoId: someId }); // someId may be stale
// after
const motion = await getAsset(motionId);
if (!motion) { throw new Error('motion asset missing, re-upload'); }
await updateAsset({ id, livePhotoVideoId: motion.id }); Defensive patterns
Strategy: validation
Validate before calling
// before linking, confirm the motion asset exists for this user
const motion = await assetRepository.getById(livePhotoVideoId);
if (!motion) { /* surface a friendly error instead of throwing deep in onBeforeLink */ }
Type guard
// runtime guard for the link payload
const isLivePhotoLinkDto = (v: any): v is { livePhotoVideoId: string } =>
typeof v?.livePhotoVideoId === 'string' && v.livePhotoVideoId.length > 0; Try / catch
// catch BadRequestException around the update call and map 'Live photo video not found' to a retry-upload UX
try { await updateAsset({ id, livePhotoVideoId }); }
catch (e) { if (e instanceof BadRequestException && /Live photo video not found/.test(e.message)) { await reuploadMotionVideo(); } else throw e; } Prevention
- Always upload the motion video first and persist its returned id before issuing the link request.
- In the client, disable the 'link live photo' action until a valid motion asset id is confirmed.
- Add an integration test that links only freshly-uploaded motion ids.
When it happens
Trigger: PUT/PATCH /assets/:id (AssetService.update) with dto.livePhotoVideoId set to a value that does not match any asset row, or POST /assets (asset-media upload) passing a livePhotoVideoId that was never persisted (e.g. the motion-video upload failed or returned an id the client fabricated).
Common situations: Client sends a stale or fabricated livePhotoVideoId after the companion motion video upload failed/timed out; race where the motion asset was deleted between upload and link; test/seed data referencing an id that no longer exists.
Related errors
- Live photo video must be a video
- May not request original file
- Asset not found or asset is not a video
- Both assets must exist
- Source and target id must be distinct
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/1df72b73bfb5a5a7.
Report an issue: GitHub.