immich-app/immich · warning · BadRequestException

Editing GIF images is not supported

Error message

Editing GIF images is not supported

What it means

Thrown by editAsset when asset.originalPath ends with '.gif' (case-insensitive). GIFs are animated/animated-container images that the raster editor cannot transform safely, so they are rejected with 400 BadRequest before edits are applied.

Source

Thrown at server/src/services/asset.service.ts:548

    const asset = await this.assetRepository.getForEdit(id);
    if (!asset) {
      throw new BadRequestException('Asset not found');
    }

    if (asset.type !== AssetType.Image) {
      throw new BadRequestException('Only images can be edited');
    }

    if (asset.livePhotoVideoId) {
      throw new BadRequestException('Editing live photos is not supported');
    }

    if (isPanorama(asset)) {
      throw new BadRequestException('Editing panorama images is not supported');
    }

    if (asset.originalPath?.toLowerCase().endsWith('.gif')) {
      throw new BadRequestException('Editing GIF images is not supported');
    }

    if (asset.originalPath?.toLowerCase().endsWith('.svg')) {
      throw new BadRequestException('Editing SVG images is not supported');
    }

    // check that crop parameters will not go out of bounds
    const { width: assetWidth, height: assetHeight } = getDimensions(asset);

    if (!assetWidth || !assetHeight) {
      throw new BadRequestException('Asset dimensions are not available for editing');
    }

    const edits = dto.edits as AssetEditActionItem[];
    const crop = edits.find((e) => e.action === AssetEditAction.Crop);
    if (crop) {
      if (edits[0].action !== AssetEditAction.Crop) {
        throw new BadRequestException('Crop action must be the first edit action');

View on GitHub (pinned to 199723261c)

Solutions

  1. Disable the editor for assets whose originalPath/originalFileName ends in .gif (case-insensitive).
  2. Convert the GIF to a static PNG/JPEG asset first if a single-frame edit is required.

Example fix

// before
const editable = asset.type === 'IMAGE';

// after
const path = (asset.originalPath ?? asset.originalFileName ?? '').toLowerCase();
const editable = asset.type === 'IMAGE' && !path.endsWith('.gif');
Defensive patterns

Strategy: validation

Validate before calling

const path = (asset.originalPath ?? asset.originalFileName ?? '').toLowerCase();
if (path.endsWith('.gif')) {
  throw new Error('GIF assets cannot be edited.');
}
await api.put(`/assets/${asset.id}/edits`, { edits });

Type guard

const isGif = (a: { originalPath?: string; originalFileName?: string }): boolean =>
  (a?.originalPath ?? a?.originalFileName ?? '').toLowerCase().endsWith('.gif');

Prevention

When it happens

Trigger: PUT /assets/{id}/edits on an asset whose stored originalPath has a .gif extension.

Common situations: User imports GIFs alongside photos; client enables editing without checking extension; case-variant .GIF uploads that get lowercased by the path check.

Related errors


AI-assisted analysis of immich-app/immich@199723261c (2026-08-12). Data as JSON: /api/errors/b3e2b3e6ba428af5. Report an issue: GitHub.