immich-app/immich · error · BadRequestException
Editing GIF images is not supported
Error message
Editing GIF images is not supported
What it means
editAsset rejects GIF files: when asset.originalPath ends with '.gif' (case-insensitive), it throws BadRequestException('Editing GIF images is not supported'). Animated GIFs cannot be safely cropped/rotated via the edit pipeline, so the operation is blocked.
Solutions
- Check the asset's originalPath/originalFileName for a .gif extension before offering or submitting edits
- Skip GIFs in bulk edit flows with a user-visible reason
- Convert the GIF to a static image (PNG/JPEG) and re-upload if a still edit is required
- Handle the 400 'Editing GIF images is not supported' response gracefully in edit tooling
Example fix
// before
await applyEdits(gifAssetId, edits);
// after
if (asset.originalPath.toLowerCase().endsWith('.gif')) return skip('gif');
await applyEdits(gifAssetId, edits); Defensive patterns
Strategy: validation
Validate before calling
if (asset.originalPath?.toLowerCase().endsWith('.gif')) throw new Error(`Asset ${asset.id} is a GIF; editing not supported`); Type guard
const isGif = (a: { originalPath?: string | null }) => !!a.originalPath && a.originalPath.toLowerCase().endsWith('.gif'); Try / catch
try { await api.applyEdits(id, edits); } catch (e) { if (String(e?.response?.data?.message).includes('GIF')) { markUnsupported(id, 'gif'); return; } throw e; } Prevention
- Check originalFileName/originalPath extension before offering edits
- Exclude .gif assets from bulk edit pipelines
- Convert GIFs to raster stills when a static edit is needed
- Remember case-insensitive matching (.GIF too)
When it happens
Trigger: Submitting image edits for an asset whose originalPath has a .gif extension, e.g. a cropped/rotated GIF imported into the library.
Common situations: Editing images downloaded from the web that turn out to be GIFs; bulk edit scripts over a library containing memes/animated GIFs; upload pipelines that accept GIFs but later apply edit jobs to them.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Editing SVG images is not supported
- Editing live photos is not supported
- Editing panorama images is not supported
- Only images can be edited
- Asset not found
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/b3e2b3e6ba428af5.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/asset.service.ts:553
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 e55ac299a4)