invoke-ai/InvokeAI · warning · HTTPException
Not an image
Error message
Not an image
What it means
HTTP 415 raised by set_workflow_thumbnail when the uploaded file's Content-Type header is missing or does not start with 'image'. The check happens before decoding, so even a valid image sent with a wrong MIME type is rejected.
Source
Thrown at invokeai/app/api/routers/workflows.py:287
},
)
async def set_workflow_thumbnail(
current_user: CurrentUserOrDefault,
workflow_id: str = Path(description="The workflow to update"),
image: UploadFile = File(description="The image file to upload"),
):
"""Sets a workflow's thumbnail image"""
try:
existing = await asyncio.to_thread(ApiDependencies.invoker.services.workflow_records.get, workflow_id)
except WorkflowNotFoundError:
raise HTTPException(status_code=404, detail="Workflow not found")
config = ApiDependencies.invoker.services.configuration
if config.multiuser and not current_user.is_admin and existing.user_id != current_user.user_id:
raise HTTPException(status_code=403, detail="Not authorized to update this workflow")
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.workflow_thumbnails.save, workflow_id, pil_image)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@workflows_router.delete(
"/i/{workflow_id}/thumbnail",
operation_id="delete_workflow_thumbnail",View on GitHub (pinned to 0b6a024f2f)
Solutions
- Ensure the uploaded file has an image/* Content-Type (e.g. image/png, image/jpeg)
- Explicitly set the MIME type when constructing the Blob/File: new File([data], name, {type:'image/png'})
- Convert the image to PNG/JPEG before upload and set the header accordingly
- Test with curl -F "image=@thumb.png;type=image/png" to confirm the endpoint accepts it
Example fix
// before
new Blob([bytes]) // no type -> 415
// after
new Blob([bytes], { type: 'image/png' }) Defensive patterns
Strategy: validation
Validate before calling
if (!file.type.startsWith('image/')) throw new Error(`Expected image/*, got ${file.type || 'unknown'}`); Type guard
function isImageFile(f) { return typeof f?.type === 'string' && f.type.startsWith('image/'); } Try / catch
try { await uploadThumbnail(id, file); } catch (e) { if (e?.status === 415) notify('Please upload a PNG or JPEG image'); else throw e; } Prevention
- Construct upload Blobs with an explicit {type: 'image/png'} MIME type
- Normalize all thumbnails to PNG/JPEG client-side before upload
- Never let upload wrappers strip the Content-Type header
When it happens
Trigger: Uploading a file with Content-Type like application/octet-stream, text/plain, or no content type at all to the thumbnail endpoint.
Common situations: Clients building FormData with a Blob lacking a type; fetch wrappers that strip the content type; programmatic uploads (curl/scripts) that don't set the header; SVG or other non-raster files served with odd MIME types.
Related errors
- Not an image
- Failed to read image
- Failed to read image
- Video must use a browser-compatible H.264/AVC codec
- Video has no decodable frame
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/2a7f10cd61b348ed.
Report an issue: GitHub.