{"record":{"id":"635554b5a1bdb824","repo":"invoke-ai/InvokeAI","slug":"not-an-image-635554","errorCode":null,"errorMessage":"Not an image","messagePattern":"Not an image","errorType":"http","errorClass":"HTTPException","httpStatus":415,"severity":"error","filePath":"invokeai/app/api/routers/style_presets.py","lineNumber":127,"sourceCode":"    try:\n        parsed_data = json.loads(data)\n        validated_data = StylePresetFormData(**parsed_data)\n\n        name = validated_data.name\n        type = validated_data.type\n        positive_prompt = validated_data.positive_prompt\n        negative_prompt = validated_data.negative_prompt\n        is_public = validated_data.is_public\n\n    except (json.JSONDecodeError, pydantic.ValidationError):\n        raise HTTPException(status_code=400, detail=\"Invalid preset data\")\n\n    record = await asyncio.to_thread(_load_record_or_404, style_preset_id)\n    _assert_preset_write(record, current_user)\n\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)","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/api/routers/style_presets.py#L109-L145","documentation":"update_style_preset checks the uploaded file's content_type: if it is missing or does not start with 'image', the endpoint returns HTTP 415 'Not an image'. This guards the PIL decode path, which only accepts image data. It is an Unsupported Media Type rejection based on the multipart part's declared MIME type.","triggerScenarios":"PATCH /style_presets/i/{id} with an optional image part whose Content-Type is absent, application/json, text/plain, application/pdf, application/octet-stream, or any non-image/* type.","commonSituations":"HTTP clients that don't set MIME type on blobs (e.g. fetch with a raw Blob lacking type); uploading placeholder .txt or .pdf files; proxies stripping Content-Type on multipart parts; test harnesses sending the image as a plain string field.","solutions":["Send the file so its part has an image/* Content-Type (e.g. image/png, image/jpeg).","Set Blob.type / File MIME type in the browser client before appending to FormData.","Verify the server actually received the file: if the client intends no image, omit the image part entirely (default None) rather than sending an empty non-typed part.","Prefer sending a real image file; if you must send arbitrary bytes, convert to PNG client-side first."],"exampleFix":"// before\nconst blob = new Blob([bytes]); // no type -> content_type null\nformData.append(\"image\", blob);\n\n// after\nconst blob = new Blob([bytes], { type: \"image/png\" });\nformData.append(\"image\", blob, \"preset.png\");","handlingStrategy":"validation","validationCode":"function canUploadImage(file) {\n  return !!file && typeof file.type === \"string\" && file.type.startsWith(\"image/\") && file.size > 0;\n}\n\nif (image && !canUploadImage(image)) throw new Error(`refusing upload: content-type=${image?.type}`);","typeGuard":"function isImageFile(f: unknown): f is File {\n  return f instanceof File && f.type.startsWith(\"image/\") && f.size > 0;\n}","tryCatchPattern":"try {\n  await api.updateStylePreset({ stylePresetId, data, image });\n} catch (e) {\n  if (e.status === 415 && e.detail === \"Not an image\") {\n    console.error(\"Image part content-type is not image/*:\", image?.type);\n  } else throw e;\n}","preventionTips":["Check file.type.startsWith('image/') before appending to FormData.","Construct Blobs with an explicit { type: 'image/png' }.","Omit the image field entirely when no image is intended.","Inspect the outgoing multipart Content-Type in devtools during integration tests."],"tags":["http-415","content-type","file-upload","fastapi"],"backgroundTag":"unsupported-media-type","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}