{"record":{"id":"2a7f10cd61b348ed","repo":"invoke-ai/InvokeAI","slug":"not-an-image-2a7f10","errorCode":null,"errorMessage":"Not an image","messagePattern":"Not an image","errorType":"http","errorClass":"HTTPException","httpStatus":415,"severity":"warning","filePath":"invokeai/app/api/routers/workflows.py","lineNumber":287,"sourceCode":"    },\n)\nasync def set_workflow_thumbnail(\n    current_user: CurrentUserOrDefault,\n    workflow_id: str = Path(description=\"The workflow to update\"),\n    image: UploadFile = File(description=\"The image file to upload\"),\n):\n    \"\"\"Sets a workflow's thumbnail image\"\"\"\n    try:\n        existing = await asyncio.to_thread(ApiDependencies.invoker.services.workflow_records.get, workflow_id)\n    except WorkflowNotFoundError:\n        raise HTTPException(status_code=404, detail=\"Workflow not found\")\n\n    config = ApiDependencies.invoker.services.configuration\n    if config.multiuser and not current_user.is_admin and existing.user_id != current_user.user_id:\n        raise HTTPException(status_code=403, detail=\"Not authorized to update this workflow\")\n\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(ApiDependencies.invoker.services.workflow_thumbnails.save, workflow_id, pil_image)\n    except Exception as e:\n        raise HTTPException(status_code=500, detail=str(e))\n\n\n@workflows_router.delete(\n    \"/i/{workflow_id}/thumbnail\",\n    operation_id=\"delete_workflow_thumbnail\",","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/api/routers/workflows.py#L269-L305","documentation":"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.","triggerScenarios":"Uploading a file with Content-Type like application/octet-stream, text/plain, or no content type at all to the thumbnail endpoint.","commonSituations":"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.","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"],"exampleFix":"// before\nnew Blob([bytes]) // no type -> 415\n// after\nnew Blob([bytes], { type: 'image/png' })","handlingStrategy":"validation","validationCode":"if (!file.type.startsWith('image/')) throw new Error(`Expected image/*, got ${file.type || 'unknown'}`);","typeGuard":"function isImageFile(f) { return typeof f?.type === 'string' && f.type.startsWith('image/'); }","tryCatchPattern":"try { await uploadThumbnail(id, file); } catch (e) { if (e?.status === 415) notify('Please upload a PNG or JPEG image'); else throw e; }","preventionTips":["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"],"tags":["http-415","content-type","upload","thumbnail"],"backgroundTag":"unsupported-media-type","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}