invoke-ai/InvokeAI · error · HTTPException
Not an image
Error message
Not an image
What it means
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.
Source
Thrown at invokeai/app/api/routers/style_presets.py:127
try:
parsed_data = json.loads(data)
validated_data = StylePresetFormData(**parsed_data)
name = validated_data.name
type = validated_data.type
positive_prompt = validated_data.positive_prompt
negative_prompt = validated_data.negative_prompt
is_public = validated_data.is_public
except (json.JSONDecodeError, pydantic.ValidationError):
raise HTTPException(status_code=400, detail="Invalid preset data")
record = await asyncio.to_thread(_load_record_or_404, style_preset_id)
_assert_preset_write(record, current_user)
if image is not None:
if not image.content_type or not image.content_type.startswith("image"):
raise HTTPException(status_code=415, detail="Not an image")
contents = await image.read()
try:
pil_image = await asyncio.to_thread(Image.open, io.BytesIO(contents))
except Exception:
ApiDependencies.invoker.services.logger.error(traceback.format_exc())
raise HTTPException(status_code=415, detail="Failed to read image")
try:
await asyncio.to_thread(
ApiDependencies.invoker.services.style_preset_image_files.save, style_preset_id, pil_image
)
except ValueError as e:
raise HTTPException(status_code=409, detail=str(e))
else:
try:
await asyncio.to_thread(ApiDependencies.invoker.services.style_preset_image_files.delete, style_preset_id)View on GitHub (pinned to 0b6a024f2f)
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.
Example fix
// before
const blob = new Blob([bytes]); // no type -> content_type null
formData.append("image", blob);
// after
const blob = new Blob([bytes], { type: "image/png" });
formData.append("image", blob, "preset.png"); Defensive patterns
Strategy: validation
Validate before calling
function canUploadImage(file) {
return !!file && typeof file.type === "string" && file.type.startsWith("image/") && file.size > 0;
}
if (image && !canUploadImage(image)) throw new Error(`refusing upload: content-type=${image?.type}`); Type guard
function isImageFile(f: unknown): f is File {
return f instanceof File && f.type.startsWith("image/") && f.size > 0;
} Try / catch
try {
await api.updateStylePreset({ stylePresetId, data, image });
} catch (e) {
if (e.status === 415 && e.detail === "Not an image") {
console.error("Image part content-type is not image/*:", image?.type);
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Failed to read image
- Not an image
- Administrator account already configured
- Error retrieving recall parameters
- Unexpected error while enqueuing batch: {e}
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/635554b5a1bdb824.
Report an issue: GitHub.