{"record":{"id":"80aadecf36375f73","repo":"invoke-ai/InvokeAI","slug":"str-e-80aade","errorCode":null,"errorMessage":"str(e)","messagePattern":"str\\(e\\)","errorType":"http","errorClass":"HTTPException","httpStatus":409,"severity":"warning","filePath":"invokeai/app/api/routers/style_presets.py","lineNumber":142,"sourceCode":"\n    if image is not None:\n        if not image.content_type or not image.content_type.startswith(\"image\"):\n            raise HTTPException(status_code=415, detail=\"Not an image\")\n\n        contents = await image.read()\n        try:\n            pil_image = await asyncio.to_thread(Image.open, io.BytesIO(contents))\n\n        except Exception:\n            ApiDependencies.invoker.services.logger.error(traceback.format_exc())\n            raise HTTPException(status_code=415, detail=\"Failed to read image\")\n\n        try:\n            await asyncio.to_thread(\n                ApiDependencies.invoker.services.style_preset_image_files.save, style_preset_id, pil_image\n            )\n        except ValueError as e:\n            raise HTTPException(status_code=409, detail=str(e))\n    else:\n        try:\n            await asyncio.to_thread(ApiDependencies.invoker.services.style_preset_image_files.delete, style_preset_id)\n        except StylePresetImageFileNotFoundException:\n            pass\n\n    preset_data = PresetData(positive_prompt=positive_prompt, negative_prompt=negative_prompt)\n    changes = StylePresetChanges(name=name, preset_data=preset_data, type=type, is_public=is_public)\n\n    style_preset_image = await asyncio.to_thread(\n        ApiDependencies.invoker.services.style_preset_image_files.get_url, style_preset_id\n    )\n    style_preset = await asyncio.to_thread(\n        ApiDependencies.invoker.services.style_preset_records.update,\n        style_preset_id=style_preset_id,\n        changes=changes,\n    )\n    return StylePresetRecordWithImage(image=style_preset_image, **style_preset.model_dump())","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/api/routers/style_presets.py#L124-L160","documentation":"When saving the preset image, style_preset_image_files.save raises ValueError (e.g. the service rejects the image, such as invalid dimensions/format constraints), and the endpoint re-raises it as HTTP 409 with the ValueError message as the detail. The generic 'str(e)' means the exact text comes from the file-saving service, not a fixed string.","triggerScenarios":"PATCH /style_presets/i/{id} with a valid decodable image whose save is rejected by the image file service — typically images violating the service's constraints (oversized dimensions, format the saver refuses, path/validation checks inside save).","commonSituations":"Uploading extremely large or extreme-aspect images; a saver that enforces max dimensions (e.g. 2k/4k limit); calling update on a preset whose storage backend is in a bad state; version changes to the image file service's accepted constraints.","solutions":["Read the 409 detail string — it is the service's ValueError and usually names the violated constraint.","Downscale or crop the image (e.g. to <=2048px) and re-upload as PNG/JPEG.","Retry with a known-good small test image to confirm the constraint, then fix the source image accordingly.","If the constraint seems wrong for your install, check the image file service configuration / InvokeAI version for changed limits."],"exampleFix":"// before\nconst img = await loadImage(hugeFile); // 12000x8000 -> save() ValueError\n\n// after\nconst img = await loadImage(hugeFile);\nconst scaled = scaleToFit(img, 2048, 2048); // respect saver constraints\nawait uploadImage(scaled);","handlingStrategy":"try-catch","validationCode":"const MAX_DIM = 2048;\nasync function assertImageWithinLimits(file) {\n  const bmp = await createImageBitmap(file);\n  if (bmp.width > MAX_DIM || bmp.height > MAX_DIM || bmp.width <= 0 || bmp.height <= 0) {\n    throw new Error(`image ${bmp.width}x${bmp.height} exceeds saver limits`);\n  }\n}","typeGuard":"function isWithinSaverLimits(img: { width: number; height: number }): boolean {\n  return img.width > 0 && img.height > 0 && img.width <= 2048 && img.height <= 2048;\n}","tryCatchPattern":"try {\n  await api.updateStylePreset({ stylePresetId, data, image });\n} catch (e) {\n  if (e.status === 409) {\n    // detail is the saver's ValueError message — show it and offer resize+retry\n    const resized = await scaleToFit(image, 2048, 2048);\n    await api.updateStylePreset({ stylePresetId, data, image: resized });\n  } else throw e;\n}","preventionTips":["Downscale images to <=2048px on the longest edge before upload.","Surface 409 detail strings to users instead of swallowing them.","Retry once with a resized/converted image on 409.","Pin/verify saver constraints after upgrading InvokeAI."],"tags":["http-409","image-upload","validation","conflict"],"backgroundTag":"image-constraint-violation","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}