{"record":{"id":"2011ac64359b2a84","repo":"immich-app/immich","slug":"asset-dimensions-are-not-available-for-editing","errorCode":null,"errorMessage":"Asset dimensions are not available for editing","messagePattern":"Asset dimensions are not available for editing","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"server/src/services/asset.service.ts","lineNumber":564,"sourceCode":"    }\n\n    if (isPanorama(asset)) {\n      throw new BadRequestException('Editing panorama images is not supported');\n    }\n\n    if (asset.originalPath?.toLowerCase().endsWith('.gif')) {\n      throw new BadRequestException('Editing GIF images is not supported');\n    }\n\n    if (asset.originalPath?.toLowerCase().endsWith('.svg')) {\n      throw new BadRequestException('Editing SVG images is not supported');\n    }\n\n    // check that crop parameters will not go out of bounds\n    const { width: assetWidth, height: assetHeight } = getDimensions(asset);\n\n    if (!assetWidth || !assetHeight) {\n      throw new BadRequestException('Asset dimensions are not available for editing');\n    }\n\n    const edits = dto.edits as AssetEditActionItem[];\n    const crop = edits.find((e) => e.action === AssetEditAction.Crop);\n    if (crop) {\n      if (edits[0].action !== AssetEditAction.Crop) {\n        throw new BadRequestException('Crop action must be the first edit action');\n      }\n\n      // check that crop parameters will not go out of bounds\n      const { width: assetWidth, height: assetHeight } = getDimensions(asset);\n\n      if (!assetWidth || !assetHeight) {\n        throw new BadRequestException('Asset dimensions are not available for editing');\n      }\n\n      const { x, y, width, height } = crop.parameters;\n      if (x + width > assetWidth || y + height > assetHeight) {","sourceCodeStart":546,"sourceCodeEnd":582,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/services/asset.service.ts#L546-L582","documentation":"editAsset validates that the asset has known width/height (from getDimensions) before applying edit actions. Immich throws this BadRequestException when the stored asset lacks dimension metadata, since crop/rotate/flip math cannot be performed on an image of unknown size. It is a client-facing 400, meaning the request itself is fine but the asset state is not editable.","triggerScenarios":"PUT /api/assets/:id (editAsset) when the resolved asset's `exifInfo`/dimensions are missing or zero — i.e. getDimensions(asset) returns width or height of 0/undefined. This happens before any edit action (crop or otherwise) is applied.","commonSituations":"Assets uploaded before metadata extraction completed or that failed extraction (e.g. unsupported video codec, sidecar-less videos, corrupted files); assets migrated from an older Immich version where dimensions were never backfilled; non-visual assets passed to the edit endpoint.","solutions":["Wait for/re-run metadata extraction for the asset so width/height are populated (queue the AssetMetadataExtraction job), then retry the edit.","Check the asset's exifInfo via GET /api/assets/:id; if width/height are null, fix the source file or re-upload it.","If assets are stuck after migration, run a metadata backfill (re-generate thumbnails / re-extract metadata in admin jobs).","Guard client-side: only call the edit endpoint for assets with known dimensions."],"exampleFix":"// client-side guard before editing\nconst asset = await api.getAsset(assetId);\nif (!asset.exifInfo?.exifImageWidth || !asset.exifInfo?.exifImageHeight) {\n  throw new Error('Asset has no dimensions yet; wait for metadata extraction');\n}\nawait api.editAsset(assetId, { edits });","handlingStrategy":"validation","validationCode":"const asset = await api.getAsset(assetId);\nif (!asset.exifInfo?.exifImageWidth || !asset.exifInfo?.exifImageHeight) {\n  throw new Error(`Asset ${assetId} has no dimensions; skip edit`);\n}","typeGuard":null,"tryCatchPattern":"try { await api.editAsset(assetId, { edits }); } catch (e) { if (e.status === 400) queueMetadataRetry(assetId); else throw e; }","preventionTips":["Only enable edit UI once metadata extraction for the asset has completed","Poll asset exifInfo before offering crop/rotate controls","Backfill metadata after restores/migrations before allowing edits"],"tags":["api","validation","metadata","immich"],"backgroundTag":"missing-required-config-field","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"}