immich-app/immich · warning

Skipping thumbnail generation for asset

Error message

Skipping thumbnail generation for asset ${id}: ${asset.type} is not an image or video

What it means

Thumbnail generation only supports AssetType.Video and AssetType.Image. If the asset's type enum holds any other value (or an unexpected type string), the handler logs this warning and returns JobStatus.Skipped rather than throwing on an unhandled media kind.

Solutions

  1. Inspect the row: SELECT type FROM asset WHERE id = '<id>'; and correct it to IMAGE or VIDEO if wrong
  2. Re-upload the asset if type detection corrupted it
  3. Re-run metadata extraction to re-derive the asset type
  4. Update the server to a version that handles the asset type in question

Example fix

// before
} else { this.logger.warn(`Skipping thumbnail generation for asset ${id}: ${asset.type} is not an image or video`); return JobStatus.Skipped; }
// after
} else { this.logger.warn(`Skipping thumbnail generation for asset ${id}: ${asset.type} is not an image or video`); await this.assetRepository.update({ id, type: await detectType(asset.originalPath) }); return JobStatus.Failed; }
Defensive patterns

Strategy: type-guard

Validate before calling

if (asset.type !== AssetType.Image && asset.type !== AssetType.Video) {
  // re-run metadata extraction or flag the asset for review
}

Type guard

function isThumbnailable(t: AssetType): boolean { return t === AssetType.Image || t === AssetType.Video; }

Try / catch

if (!isThumbnailable(asset.type)) { this.logger.warn(`Skipping thumbnail generation for asset ${id}: ${asset.type}`); return JobStatus.Skipped; }

Prevention

When it happens

Trigger: handleGenerateThumbnails receives an asset whose asset.type is neither Video nor Image — typically a malformed type value in the database or a newly introduced type not yet handled by the media service.

Common situations: Manually edited or migrated database rows with unexpected type values; uploads whose type detection misclassified the file; running an older server against a database written by a newer version that added a type.

Related errors


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

Appendix: source

Thrown at server/src/services/media.service.ts:216

    if (!asset) {
      this.logger.warn(`Thumbnail generation failed for asset ${id}: not found in database or missing metadata`);
      return JobStatus.Failed;
    }

    if (asset.visibility === AssetVisibility.Hidden) {
      this.logger.verbose(`Thumbnail generation skipped for asset ${id}: not visible`);
      return JobStatus.Skipped;
    }

    let generated: Awaited<ReturnType<MediaService['generateImageThumbnails']>>;
    if (asset.type === AssetType.Video || asset.originalFileName.toLowerCase().endsWith('.gif')) {
      this.logger.verbose(`Thumbnail generation for video ${id} ${asset.originalPath}`);
      generated = await this.generateVideoThumbnails(asset, config);
    } else if (asset.type === AssetType.Image) {
      this.logger.verbose(`Thumbnail generation for image ${id} ${asset.originalPath}`);
      generated = await this.generateImageThumbnails(asset, config);
    } else {
      this.logger.warn(`Skipping thumbnail generation for asset ${id}: ${asset.type} is not an image or video`);
      return JobStatus.Skipped;
    }

    const editedGenerated = await this.generateEditedThumbnails(asset, config);
    if (editedGenerated) {
      generated.files.push(...editedGenerated.files);
    }

    await this.syncFiles(asset.files, generated.files);
    const thumbhash = editedGenerated?.thumbhash || generated.thumbhash;

    if (!asset.thumbhash || Buffer.compare(asset.thumbhash, thumbhash) !== 0) {
      await this.assetRepository.update({ id: asset.id, thumbhash });
    }

    return JobStatus.Success;
  }

View on GitHub (pinned to e55ac299a4)