mirror of
https://github.com/open-webui/open-webui.git
synced 2026-05-24 11:58:31 -05:00
[GH-ISSUE #24565] issue: edit_image with ComfyUI no longer returns images in 0.9.5 #74940
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @seamon67 on GitHub (May 11, 2026).
Original GitHub issue: https://github.com/open-webui/open-webui/issues/24565
Check Existing Issues
Installation Method
Docker
Open WebUI Version
0.9.5
Ollama Version (if applicable)
No response
Operating System
Linux
Browser (if applicable)
No response
Confirmation
README.md.Expected Behavior
edit_image when used with ComfyUI should work and return an image to be displayer to the user.
Actual Behavior
"error": "400: [ERROR: 'NoneType' object has no attribute 'lower']"Steps to Reproduce
Logs & Screenshots
Traceback (most recent call last):
File "", line 198, in _run_module_as_main
File "", line 88, in _run_code
File "/usr/local/lib/python3.11/site-packages/uvicorn/main.py", line 4, in
uvicorn.main()
│ └
└ <module 'uvicorn' from '/usr/local/lib/python3.11/site-packages/uvicorn/init.py'>
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1514, in call
return self.main(args, **kwargs)
│ │ │ └ {}
│ │ └ ()
│ └ <function Command.main at 0x14ade80ff240>
└
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1435, in main
rv = self.invoke(ctx)
│ │ └ <click.core.Context object at 0x14ade8df50d0>
│ └ <function Command.invoke at 0x14ade80fef20>
└
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1298, in invoke
return ctx.invoke(self.callback, **ctx.params)
│ │ │ │ │ └ {'host': '0.0.0.0', 'port': 8080, 'forwarded_allow_ips': '', 'workers': 1, 'app': 'open_webui.main:app', 'uds': None, 'fd': ...
│ │ │ │ └ <click.core.Context object at 0x14ade8df50d0>
│ │ │ └ <function main at 0x14ade7ed42c0>
│ │ └
│ └ <function Context.invoke at 0x14ade80fe160>
└ <click.core.Context object at 0x14ade8df50d0>
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 853, in invoke
return callback(args, **kwargs)
│ │ └ {'host': '0.0.0.0', 'port': 8080, 'forwarded_allow_ips': '', 'workers': 1, 'app': 'open_webui.main:app', 'uds': None, 'fd': ...
│ └ ()
└ <function main at 0x14ade7ed42c0>
File "/usr/local/lib/python3.11/site-packages/uvicorn/main.py", line 433, in main
run(
└ <function run at 0x14ade7f95ee0>
File "/usr/local/lib/python3.11/site-packages/uvicorn/main.py", line 606, in run
server.run()
│ └ <function Server.run at 0x14ade7f95760>
└ <uvicorn.server.Server object at 0x14ade8133e50>
File "/usr/local/lib/python3.11/site-packages/uvicorn/server.py", line 75, in run
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
│ │ │ │ │ │ └ <function Config.get_loop_factory at 0x14ade80cc400>
│ │ │ │ │ └ <uvicorn.config.Config object at 0x14ade7ed9c50>
│ │ │ │ └ <uvicorn.server.Server object at 0x14ade8133e50>
│ │ │ └ None
│ │ └ <function Server.serve at 0x14ade7f95800>
│ └ <uvicorn.server.Server object at 0x14ade8133e50>
└ <function asyncio_run at 0x14ade8102200>
File "/usr/local/lib/python3.11/site-packages/uvicorn/_compat.py", line 30, in asyncio_run
return runner.run(main)
│ │ └ <coroutine object Server.serve at 0x14ade7e3b1f0>
│ └ <function Runner.run at 0x14ade8354fe0>
└ <asyncio.runners.Runner object at 0x14ade7ee1590>
File "/usr/local/lib/python3.11/asyncio/runners.py", line 118, in run
return self._loop.run_until_complete(task)
│ │ │ └ <Task pending name='Task-1' coro=<Server.serve() running at /usr/local/lib/python3.11/site-packages/uvicorn/server.py:79> wai...
│ │ └ <cyfunction Loop.run_until_complete at 0x14ade7bfa740>
│ └ <uvloop.Loop running=True closed=False debug=False>
└ <asyncio.runners.Runner object at 0x14ade7ee1590>
File "/app/backend/open_webui/main.py", line 1997, in process_chat
return await process_chat_response(response, ctx)
│ │ └ {'request': <starlette.requests.Request object at 0x14ad71a817d0>, 'form_data': {'stream': True, 'model': 'Gemma:31b', 'strea...
│ └ <starlette.responses.StreamingResponse object at 0x14ad730893d0>
└ <function process_chat_response at 0x14ad77514360>
File "/app/backend/open_webui/utils/middleware.py", line 5204, in process_chat_response
return await streaming_chat_response_handler(response, ctx)
│ │ └ {'request': <starlette.requests.Request object at 0x14ad71a817d0>, 'form_data': {'stream': True, 'model': 'Gemma:31b', 'strea...
│ └ <starlette.responses.StreamingResponse object at 0x14ad730893d0>
└ <function streaming_chat_response_handler at 0x14ad775142c0>
File "/app/backend/open_webui/utils/middleware.py", line 5152, in streaming_chat_response_handler
return await response_handler(response, events)
│ │ └ []
│ └ <starlette.responses.StreamingResponse object at 0x14ad730893d0>
└ <function streaming_chat_response_handler..response_handler at 0x14ad095b3060>
File "/app/backend/open_webui/utils/middleware.py", line 4599, in response_handler
tool_result = await tool_function(**tool_function_params)
│ └ {'image_urls': ['/api/v1/files/c3c9da27-194e-4c1d-9c14-532d487e74d9/content'], 'prompt': 'Insert the following translated Eng...
└ <function edit_image at 0x14ad71dd5c60>
File "/app/backend/open_webui/utils/tools.py", line 136, in new_function
return await partial_func(*args, **kwargs)
│ │ └ {'image_urls': ['/api/v1/files/c3c9da27-194e-4c1d-9c14-532d487e74d9/content'], 'prompt': 'Insert the following translated Eng...
│ └ ()
└ functools.partial(<function edit_image at 0x14ad7753c5e0>, request=<starlette.requests.Request object at 0x14ad71a817d0>,...
File "/app/backend/open_webui/tools/builtin.py", line 347, in edit_image
images = await image_edits(
└ <function image_edits at 0x14ad78270220>
File "/app/backend/open_webui/routers/images.py", line 1069, in image_edits
image_data, content_type = await get_image_data(image_url, headers)
│ │ └ None
│ └ 'http://host:8188/view?filename=Flux-2-Klein+Edit_00020_.png&subfolder=&type=output'
└ <function get_image_data at 0x14ad7839f9c0>
File "/app/backend/open_webui/retrieval/web/utils.py", line 70, in validate_url
raise ValueError(ERROR_MESSAGES.INVALID_URL)
│ └ <ERROR_MESSAGES.INVALID_URL: 'Oops! The URL you provided is invalid. Please double-check and try again.'>
└ <enum 'ERROR_MESSAGES'>
ValueError: Oops! The URL you provided is invalid. Please double-check and try again.
2026-05-11 12:09:37.525 | ERROR | open_webui.tools.builtin:edit_image:388 - edit_image error: 400: [ERROR: 'NoneType' object has no attribute 'lower']
Traceback (most recent call last):
File "/app/backend/open_webui/routers/images.py", line 1070, in image_edits
_, url = await upload_image(
└ <function upload_image at 0x14ad7839fe20>
File "/app/backend/open_webui/routers/images.py", line 475, in upload_image
image_format = mimetypes.guess_extension(content_type)
│ │ └ None
│ └ <function guess_extension at 0x14ade787f420>
└ <module 'mimetypes' from '/usr/local/lib/python3.11/mimetypes.py'>
File "/usr/local/lib/python3.11/mimetypes.py", line 347, in guess_extension
return _db.guess_extension(type, strict)
│ │ │ └ True
│ │ └ None
│ └ <function MimeTypes.guess_extension at 0x14ade787f060>
└ <mimetypes.MimeTypes object at 0x14ad75ba4090>
File "/usr/local/lib/python3.11/mimetypes.py", line 202, in guess_extension
extensions = self.guess_all_extensions(type, strict)
│ │ │ └ True
│ │ └ None
│ └ <function MimeTypes.guess_all_extensions at 0x14ade787efc0>
└ <mimetypes.MimeTypes object at 0x14ad75ba4090>
File "/usr/local/lib/python3.11/mimetypes.py", line 181, in guess_all_extensions
type = type.lower()
└ None
AttributeError: 'NoneType' object has no attribute 'lower'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "", line 198, in _run_module_as_main
File "", line 88, in _run_code
File "/usr/local/lib/python3.11/site-packages/uvicorn/main.py", line 4, in
uvicorn.main()
│ └
└ <module 'uvicorn' from '/usr/local/lib/python3.11/site-packages/uvicorn/init.py'>
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1514, in call
return self.main(args, **kwargs)
│ │ │ └ {}
│ │ └ ()
│ └ <function Command.main at 0x14ade80ff240>
└
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1435, in main
rv = self.invoke(ctx)
│ │ └ <click.core.Context object at 0x14ade8df50d0>
│ └ <function Command.invoke at 0x14ade80fef20>
└
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1298, in invoke
return ctx.invoke(self.callback, **ctx.params)
│ │ │ │ │ └ {'host': '0.0.0.0', 'port': 8080, 'forwarded_allow_ips': '', 'workers': 1, 'app': 'open_webui.main:app', 'uds': None, 'fd': ...
│ │ │ │ └ <click.core.Context object at 0x14ade8df50d0>
│ │ │ └ <function main at 0x14ade7ed42c0>
│ │ └
│ └ <function Context.invoke at 0x14ade80fe160>
└ <click.core.Context object at 0x14ade8df50d0>
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 853, in invoke
return callback(args, **kwargs)
│ │ └ {'host': '0.0.0.0', 'port': 8080, 'forwarded_allow_ips': '', 'workers': 1, 'app': 'open_webui.main:app', 'uds': None, 'fd': ...
│ └ ()
└ <function main at 0x14ade7ed42c0>
File "/usr/local/lib/python3.11/site-packages/uvicorn/main.py", line 433, in main
run(
└ <function run at 0x14ade7f95ee0>
File "/usr/local/lib/python3.11/site-packages/uvicorn/main.py", line 606, in run
server.run()
│ └ <function Server.run at 0x14ade7f95760>
└ <uvicorn.server.Server object at 0x14ade8133e50>
File "/usr/local/lib/python3.11/site-packages/uvicorn/server.py", line 75, in run
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
│ │ │ │ │ │ └ <function Config.get_loop_factory at 0x14ade80cc400>
│ │ │ │ │ └ <uvicorn.config.Config object at 0x14ade7ed9c50>
│ │ │ │ └ <uvicorn.server.Server object at 0x14ade8133e50>
│ │ │ └ None
│ │ └ <function Server.serve at 0x14ade7f95800>
│ └ <uvicorn.server.Server object at 0x14ade8133e50>
└ <function asyncio_run at 0x14ade8102200>
File "/usr/local/lib/python3.11/site-packages/uvicorn/_compat.py", line 30, in asyncio_run
return runner.run(main)
│ │ └ <coroutine object Server.serve at 0x14ade7e3b1f0>
│ └ <function Runner.run at 0x14ade8354fe0>
└ <asyncio.runners.Runner object at 0x14ade7ee1590>
File "/usr/local/lib/python3.11/asyncio/runners.py", line 118, in run
return self._loop.run_until_complete(task)
│ │ │ └ <Task pending name='Task-1' coro=<Server.serve() running at /usr/local/lib/python3.11/site-packages/uvicorn/server.py:79> wai...
│ │ └ <cyfunction Loop.run_until_complete at 0x14ade7bfa740>
│ └ <uvloop.Loop running=True closed=False debug=False>
└ <asyncio.runners.Runner object at 0x14ade7ee1590>
File "/app/backend/open_webui/main.py", line 1997, in process_chat
return await process_chat_response(response, ctx)
│ │ └ {'request': <starlette.requests.Request object at 0x14ad71a817d0>, 'form_data': {'stream': True, 'model': 'Gemma:31b', 'strea...
│ └ <starlette.responses.StreamingResponse object at 0x14ad730893d0>
└ <function process_chat_response at 0x14ad77514360>
File "/app/backend/open_webui/utils/middleware.py", line 5204, in process_chat_response
return await streaming_chat_response_handler(response, ctx)
│ │ └ {'request': <starlette.requests.Request object at 0x14ad71a817d0>, 'form_data': {'stream': True, 'model': 'Gemma:31b', 'strea...
│ └ <starlette.responses.StreamingResponse object at 0x14ad730893d0>
└ <function streaming_chat_response_handler at 0x14ad775142c0>
File "/app/backend/open_webui/utils/middleware.py", line 5152, in streaming_chat_response_handler
return await response_handler(response, events)
│ │ └ []
│ └ <starlette.responses.StreamingResponse object at 0x14ad730893d0>
└ <function streaming_chat_response_handler..response_handler at 0x14ad095b3060>
File "/app/backend/open_webui/utils/middleware.py", line 4599, in response_handler
tool_result = await tool_function(**tool_function_params)
│ └ {'image_urls': ['/api/v1/files/c3c9da27-194e-4c1d-9c14-532d487e74d9/content'], 'prompt': 'Insert the following translated Eng...
└ <function edit_image at 0x14ad71dd5c60>
File "/app/backend/open_webui/utils/tools.py", line 136, in new_function
return await partial_func(*args, **kwargs)
│ │ └ {'image_urls': ['/api/v1/files/c3c9da27-194e-4c1d-9c14-532d487e74d9/content'], 'prompt': 'Insert the following translated Eng...
│ └ ()
└ functools.partial(<function edit_image at 0x14ad7753c5e0>, request=<starlette.requests.Request object at 0x14ad71a817d0>,...
File "/app/backend/open_webui/routers/images.py", line 1085, in image_edits
raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(error))
│ │ │ └ AttributeError("'NoneType' object has no attribute 'lower'")
│ │ └ <function ERROR_MESSAGES. at 0x14ade3dd89a0>
│ └ <enum 'ERROR_MESSAGES'>
└ <class 'fastapi.exceptions.HTTPException'>
fastapi.exceptions.HTTPException: 400: [ERROR: 'NoneType' object has no attribute 'lower']
Additional Information
edit_image was working perfectly in 0.9.2
I can also confirm that images are being created in ComfyUI
@owui-terminator[bot] commented on GitHub (May 11, 2026):
🔍 Related Issues Found
I found some existing issues that might be related. Please check if any of these are duplicates or contain helpful solutions:
🟣 #24271 issue: Image generation with ComfyUI failing in 0.9.2
This is the most directly related prior report: ComfyUI image generation in Open WebUI 0.9.2 was also failing while attempting to upload/display the generated image. It likely shares the same ComfyUI-to-OpenWebUI image handling path that regressed again in 0.9.5.
by jpbreda ·
bug🟣 #20754 issue: New upload of an image does not work with image editing
This issue is about the image editing flow choosing or handling the wrong reference image, which is adjacent to the same edit_image / image_edits code path. It may help if the 0.9.5 regression is due to how edited images are resolved after ComfyUI returns a file.
by iChristGit ·
bug💡 If your issue is a duplicate, please close it and add any additional details to the existing issue instead.
This comment was generated automatically. React with 👍 if helpful, 👎 if not.
@littlelucky commented on GitHub (May 11, 2026):
image generation error from 0.9.5, the img was generated by comfyui but cannot transfer to front.
0.9.4 is ok
@NinjaLane commented on GitHub (May 11, 2026):
I can confirm the same.
"edit_image was working perfectly in 0.9.2
I can also confirm that images are being created in ComfyUI"
@luciusbono commented on GitHub (May 12, 2026):
I also have this issue in 0.9.5, reverted to 0.9.3 and things are fine again.
@dongfangzan commented on GitHub (May 12, 2026):
I can confirm this exact same issue on my side.
Root cause
This regression was introduced in v0.9.5 via PR #24518 ("Image generation URL validation"), which added
validate_url()insideget_image_data(). While this hardening makes sense for externally-loaded images, it breaks the ComfyUI download path because:192.168.x.x).http://192.168.x.x:8188/view?filename=....get_image_data()callsvalidate_url()on that URL.ENABLE_RAG_LOCAL_WEB_FETCH=false,validate_urlrejects any URL that resolves to a private IP (127.0.0.0/8,10.0.0.0/8,192.168.0.0/16, etc.).get_image_data()catches theValueErrorand returns(None, None).image_edits/image_generations) does not check forNoneand passes it straight toupload_image(..., content_type=None, ...).upload_imagecallsmimetypes.guess_extension(None), which triggers the'NoneType' object has no attribute 'lower'crash.So the image generation actually succeeds; the crash happens after generation, during the download phase.
Workaround that works for me
Set the environment variable in your OpenWebUI deployment:
With this,
validate_url()no longer blocks private IPs and ComfyUI images download normally.However, this is a global switch—it disables SSRF protection for all web-fetch features (RAG web search, image loading, etc.), not just ComfyUI. It works as a short-term fix but is not ideal from a security standpoint.
Suggested proper fix
Either of these would solve the problem more cleanly:
validate_url()for URLs that originate from an internally-configured ComfyUI instance. Since the ComfyUI base URL is explicitly set by the admin, it carries no SSRF risk.image_generations/image_edits. Ifget_image_data()returns(None, None), log the failure andcontinueinstead of passingNoneintoupload_image.@littlelucky commented on GitHub (May 12, 2026):
ENABLE_RAG_LOCAL_WEB_FETCH=true
this setting is OK
@seamon67 commented on GitHub (May 12, 2026):
Was a UI Button added for this?
@jpbreda commented on GitHub (May 12, 2026):
Came here with the exact same problem. Thanks for the workaround.
A local IP address for an instance running ComfyUI is a totally valid configuration for a sovereign AI setup.
@pfn commented on GitHub (May 13, 2026):
adding a new ERROR_MESSAGES.RAG_LOCAL_DISALLOWED would be good for this circumstance, and fixing the exception path so that it bubbles the error up to the front end would be good.
right now, the .lower on None is happening because None is passed to mimetypes.guess_extension, due to the failure to fetch from local