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

  1. Ensure the uploaded file has an image/* Content-Type (e.g. image/png, image/jpeg)
  2. Explicitly set the MIME type when constructing the Blob/File: new File([data], name, {type:'image/png'})
  3. Convert the image to PNG/JPEG before upload and set the header accordingly
  4. 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

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


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/2a7f10cd61b348ed. Report an issue: GitHub.