{"record":{"id":"d3a03e4f56f42467","repo":"immich-app/immich","slug":"asset-not-found-or-asset-is-not-a-video","errorCode":null,"errorMessage":"Asset not found or asset is not a video","messagePattern":"Asset not found or asset is not a video","errorType":"http","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"server/src/services/asset-media.service.ts","lineNumber":306,"sourceCode":"    const fileNameBase =\n      auth.sharedLink && !auth.sharedLink.showExif ? id : getFileNameWithoutExtension(originalFileName);\n    const fileName = `${fileNameBase}_${size}${getFilenameExtension(path)}`;\n\n    return new ImmichFileResponse({\n      fileName,\n      path,\n      contentType: mimeTypes.lookup(path),\n      cacheControl: CacheControl.PrivateWithCache,\n    });\n  }\n\n  async playbackVideo(auth: AuthDto, id: string): Promise<ImmichFileResponse> {\n    await this.requireAccess({ auth, permission: Permission.AssetView, ids: [id] });\n\n    const asset = await this.assetRepository.getForVideo(id);\n\n    if (!asset) {\n      throw new NotFoundException('Asset not found or asset is not a video');\n    }\n\n    const filepath = asset.encodedVideoPath || asset.originalPath;\n\n    return new ImmichFileResponse({\n      path: filepath,\n      contentType: mimeTypes.lookup(filepath),\n      cacheControl: CacheControl.PrivateWithCache,\n    });\n  }\n\n  async bulkUploadCheck(auth: AuthDto, dto: AssetBulkUploadCheckDto): Promise<AssetBulkUploadCheckResponseDto> {\n    const checksums: Buffer[] = dto.assets.map((asset) => fromChecksum(asset.checksum));\n    const results = await this.assetRepository.getByChecksums(auth.user.id, checksums);\n    const checksumMap: Record<string, { id: string; isTrashed: boolean }> = {};\n\n    for (const { id, deletedAt, checksum } of results) {\n      checksumMap[checksum.toString('hex')] = { id, isTrashed: !!deletedAt };","sourceCodeStart":288,"sourceCodeEnd":324,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/server/src/services/asset-media.service.ts#L288-L324","documentation":"Thrown by AssetMediaService.playbackVideo as NotFoundException (HTTP 404) when assetRepository.getForVideo(id) returns null. getForVideo only returns rows that are videos (or have an encodedVideoPath), so the asset either does not exist or is not a video type. Playback is only valid for video assets.","triggerScenarios":"GET /assets/:id/playback where :id is a photo (not a video), or the asset id does not exist at all. Also possible if the asset exists but has no encoded video path and is not classified as a video.","commonSituations":"UI invoking playback on a non-video asset; live-photo motion asset referenced incorrectly; client guessing that an id is a video without checking type.","solutions":["Check asset.type === 'VIDEO' (or has encodedVideoPath) before calling playback","Use the appropriate endpoint for photos (thumbnail/original)","Confirm the asset id exists via GET /assets/:id first"],"exampleFix":"// before\nawait sdk.playbackAsset(maybePhotoId); // 404\n// after\nconst asset = await sdk.getAsset(maybePhotoId);\nif (asset.type !== 'VIDEO') throw new Error('not a video');\nawait sdk.playbackAsset(maybePhotoId);","handlingStrategy":"validation","validationCode":"// Only call playback for video assets\nconst asset = await sdk.getAsset(id);\nif (!asset || asset.type !== 'VIDEO') {\n  throw new Error('asset is not a video');\n}\nawait sdk.playbackAsset(id);","typeGuard":"function isVideoAsset(a: { type?: string; encodedVideoPath?: string | null }): boolean {\n  return a?.type === 'VIDEO' || !!a?.encodedVideoPath;\n}","tryCatchPattern":null,"preventionTips":["Check asset.type === 'VIDEO' before invoking playback","Use the thumbnail/original endpoint for photos","Confirm the asset id exists before requesting playback"],"tags":["asset","video","playback","not-found","validation","nestjs"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}