{"record":{"id":"e6bd553925d74cb9","repo":"immich-app/immich","slug":"editing-panorama-images-is-not-supported","errorCode":null,"errorMessage":"Editing panorama images is not supported","messagePattern":"Editing panorama images is not supported","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"server/src/services/asset.service.ts","lineNumber":544,"sourceCode":"\n  async editAsset(auth: AuthDto, id: string, dto: AssetEditsCreateDto): Promise<AssetEditsResponseDto> {\n    await this.requireAccess({ auth, permission: Permission.AssetEditCreate, ids: [id] });\n\n    const asset = await this.assetRepository.getForEdit(id);\n    if (!asset) {\n      throw new BadRequestException('Asset not found');\n    }\n\n    if (asset.type !== AssetType.Image) {\n      throw new BadRequestException('Only images can be edited');\n    }\n\n    if (asset.livePhotoVideoId) {\n      throw new BadRequestException('Editing live photos is not supported');\n    }\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[];","sourceCodeStart":526,"sourceCodeEnd":562,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/server/src/services/asset.service.ts#L526-L562","documentation":"Thrown by editAsset when isPanorama(asset) is true. Per server/src/utils/asset.util.ts, isPanorama returns true when projectionType === 'EQUIRECTANGULAR' or the originalFileName ends with '.insp' (Insta360). Panoramas need a spherical viewer and cannot be cropped/rotated as flat images, so the editor rejects them with 400 BadRequest.","triggerScenarios":"PUT /assets/{id}/edits on a 360° equirectangular panorama or an Insta360 .insp image.","commonSituations":"User has a 360 camera library; client surfaces a normal edit button on panoramic assets; metadata extraction set projectionType='EQUIRECTANGULAR' from XMP/GPano data.","solutions":["Hide/disable the flat editor when asset.projectionType === 'EQUIRECTANGULAR' or the filename ends with '.insp'.","Route panoramic assets to a spherical viewer instead.","Strip/normalize projectionType only if you intentionally want flat editing (not recommended)."],"exampleFix":"// before\nconst isPanorama = false;\n\n// after\nconst isPanorama =\n  asset.projectionType === 'EQUIRECTANGULAR' ||\n  asset.originalFileName.toLowerCase().endsWith('.insp');\nconst editable = asset.type === 'IMAGE' && !asset.livePhotoVideoId && !isPanorama;","handlingStrategy":"validation","validationCode":"const isPanorama =\n  asset.projectionType === 'EQUIRECTANGULAR' ||\n  (asset.originalFileName ?? '').toLowerCase().endsWith('.insp');\nif (isPanorama) {\n  throw new Error('Panoramas cannot be edited as flat images.');\n}","typeGuard":"function isPanoramic(a: { projectionType?: string | null; originalFileName?: string }): boolean {\n  return (\n    a?.projectionType === 'EQUIRECTANGULAR' ||\n    (a?.originalFileName ?? '').toLowerCase().endsWith('.insp')\n  );\n}","tryCatchPattern":null,"preventionTips":["Mirror the server's isPanorama rule exactly on the client.","Route equirectangular/.insp assets to a spherical viewer.","Re-check projectionType after metadata extraction completes."],"tags":["asset","edit","panorama","validation","image"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}