{"record":{"id":"1cfd13b823a4af21","repo":"immich-app/immich","slug":"asset-media-not-found","errorCode":null,"errorMessage":"Asset media not found","messagePattern":"Asset media not found","errorType":"exception","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"server/src/services/asset-media.service.ts","lineNumber":285,"sourceCode":"    const { originalPath, originalFileName, path } = await this.assetRepository.getForThumbnail(\n      id,\n      size,\n      dto.edited ?? false,\n    );\n\n    if (size === AssetFileType.FullSize && mimeTypes.isWebSupportedImage(originalPath) && !dto.edited) {\n      // use original file for web supported images\n      return { targetSize: 'original' };\n    }\n\n    if (dto.size === AssetMediaSize.FULLSIZE && !path) {\n      // downgrade to preview if fullsize is not available.\n      // e.g. disabled or not yet (re)generated\n      return { targetSize: AssetMediaSize.PREVIEW };\n    }\n\n    if (!path) {\n      throw new NotFoundException('Asset media not found');\n    }\n\n    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);","sourceCodeStart":267,"sourceCodeEnd":303,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/services/asset-media.service.ts#L267-L303","documentation":"viewThumbnail resolved the requested rendition size (with fallback from fullsize to preview when fullsize is unavailable) but the resulting file path is empty — i.e. no stored rendition file exists for this asset at any acceptable size. It throws NotFoundException('Asset media not found').","triggerScenarios":"GET /api/assets/:id/thumbnail for an asset whose preview image has not been generated yet (upload still processing, thumbnail generation job failed/disabled) and fullsize is also absent.","commonSituations":"Requesting thumbnails immediately after upload before the thumbnail job runs; storage-template or library migration left files missing; transcoding/thumbnail worker crashed; asset exists in DB but its files were removed from disk.","solutions":["Wait for background thumbnail generation to finish, then retry.","Check the Jobs status in the admin UI; re-run the 'Generate Thumbnails' job for missing assets.","Verify the storage volume is mounted and the preview paths under the data directory exist.","Confirm the asset id is correct — a wrong id pointing to a media-less record yields the same 404."],"exampleFix":"// before\nconst thumb = await getThumb(id); // 404 right after upload\n// after\nlet thumb = null;\nfor (let i = 0; i < 10 && !thumb; i++) {\n  thumb = await getThumb(id).catch(() => null);\n  if (!thumb) await sleep(2000); // wait for thumbnail job\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { return await getThumbnail(id, size); } catch (e) { if (e.status === 404) return placeholderImage(); throw e; }","preventionTips":["Delay thumbnail display until jobs (thumbnail generation) are complete","Monitor the thumbnail-generation job queue for failures","Verify storage volumes are mounted after restarts/migrations"],"tags":["not-found","thumbnail","missing-file","asset-processing"],"backgroundTag":"resource-not-found","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"}