immich-app/immich · warning

Could not find asset

Error message

Could not find asset ${item.data.id} after generating thumbnails

What it means

After thumbnail generation completes, the job handler re-fetches the asset (with all relations) to enqueue follow-up jobs like Smart Search and face detection. This warning is logged when the asset no longer exists in the database. The job intentionally breaks instead of throwing, since the follow-up work is meaningless for a deleted asset.

Solutions

  1. Confirm the asset id exists: SELECT * FROM asset WHERE id = '<id>'; if absent, the warning is expected and safe to ignore
  2. Avoid deleting assets while large thumbnail jobs are queued; pause deletion or drain the queue first
  3. If warnings appear en masse for stale queue entries, clear orphaned queue jobs (flush the thumbnail queue)
  4. If assets should exist, check DB replication/restore state and repository wiring

Example fix

// before
const [asset] = await this.assetRepository.getByIdsWithAllRelationsButStacks([item.data.id]);
if (!asset) { this.logger.warn(`Could not find asset ${item.data.id} after generating thumbnails`); break; }
// after
const [asset] = await this.assetRepository.getByIdsWithAllRelationsButStacks([item.data.id]);
if (!asset) { this.logger.verbose(`Asset ${item.data.id} deleted before post-thumbnail processing; skipping`); break; }
Defensive patterns

Strategy: type-guard

Validate before calling

const assets = await assetRepository.getByIdsWithAllRelationsButStacks([id]);
if (assets.length === 0) return; // asset deleted; skip follow-up jobs

Type guard

function isAsset(a: Asset | undefined): a is Asset { return a !== undefined; }

Try / catch

const [asset] = await this.assetRepository.getByIdsWithAllRelationsButStacks([item.data.id]);
if (!asset) { this.logger.warn(`Could not find asset ${item.data.id}`); break; }

Prevention

When it happens

Trigger: The asset row was deleted (e.g. by user deletion or a trash/truncate job) between job enqueue and job completion, so getByIdsWithAllRelationsButStacks returns an empty array.

Common situations: User deletes an asset while its thumbnail job is queued; bulk deletion running concurrently with thumbnail generation; database restored/rolled back leaving orphaned job items.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at server/src/services/job.service.ts:174

              width: asset.width,
              height: asset.height,
              isEdited: asset.isEdited,
            },
            edit: edits,
          });
        }

        break;
      }

      case JobName.AssetGenerateThumbnails: {
        if (!item.data.notify && item.data.source !== 'upload') {
          break;
        }

        const [asset] = await this.assetRepository.getByIdsWithAllRelationsButStacks([item.data.id]);
        if (!asset) {
          this.logger.warn(`Could not find asset ${item.data.id} after generating thumbnails`);
          break;
        }

        const jobs: JobItem[] = [
          { name: JobName.SmartSearch, data: item.data },
          { name: JobName.AssetDetectFaces, data: item.data },
          { name: JobName.Ocr, data: item.data },
        ];

        if (asset.type === AssetType.Video) {
          jobs.push({ name: JobName.AssetEncodeVideo, data: item.data });
        }

        await this.jobRepository.queueAll(jobs);
        if (asset.visibility === AssetVisibility.Timeline || asset.visibility === AssetVisibility.Archive) {
          this.websocketRepository.clientSend('on_upload_success', asset.ownerId, mapAsset(asset));
          if (asset.exifInfo) {
            const exif = asset.exifInfo;

View on GitHub (pinned to e55ac299a4)