mirror of
https://github.com/open-webui/open-webui.git
synced 2026-07-17 08:21:12 -05:00
[GH-ISSUE #22734] issue: Intermittent model lookup failures due to RedisDict.set() race condition #58467
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 @m1g32 on GitHub (Mar 16, 2026).
Original GitHub issue: https://github.com/open-webui/open-webui/issues/22734
Check Existing Issues
Installation Method
Docker
Open WebUI Version
v0.8.8
Ollama Version (if applicable)
No response
Operating System
Kubernetes 1.32
Browser (if applicable)
No response
Confirmation
README.md.Expected Behavior
• The selected model should always be found and consistently usable for all tasks.
• Both main response generation and follow-up tasks (follow-up question and chat title generation) should reliably use the same model without intermittent lookup failures.
Actual Behavior
• Intermittent “model not found” errors occur, even though the model does exist and is accessible at other times.
• Two failure patterns appear:
– During main response generation, the request fails entirely with “model not found”.
– During follow-up tasks (generate_follow_ups), the main response is produced successfully using the model, but follow-up question and/or chat title generation fails with “model not found” for the same model.
• The problem occurs randomly and is not tied to any specific model.
• The issue appears only in deployments under heavy load with many concurrent users, where RedisDict.set is called very frequently, and model-list refreshes become extremely common.
Steps to Reproduce
Deploy Open WebUI on Kubernetes with multiple replicas.
Deploy a Redis Cluster and configure Open WebUI accordingly.
Add several base models, then add a large number of custom models (hundreds).
Optionally set MODELS_CACHE_TTL to a non-zero value such as 300 seconds.
Leave “Cache Base Model List” enabled or disabled (the issue occurs either way).
Do not configure any dedicated local or external task model.
Under intense concurrent usage, generate responses using any available model.
Observe that intermittently:
– The main response fails with “model not found”, or
– The main response succeeds, but follow-up generation (follow-up question or chat title) fails with “model not found” for the same model.
Repeat several times; the failures occur unpredictably based on timing conditions.
Logs & Screenshots
| ERROR | open_webui.routers.tasks:generate_follow_ups:328 - Exception occurred
Traceback (most recent call last):
File "", line 1, in
File "/usr/local/lib/python3.11/multiprocessing/spawn.py", line 122, in spawn_main
exitcode = _main(fd, parent_sentinel)
│ │ └ 4
│ └ 21
└ <function _main at 0x7febd5f1e160>
File "/usr/local/lib/python3.11/multiprocessing/spawn.py", line 135, in _main
return self._bootstrap(parent_sentinel)
│ │ └ 4
│ └ <function BaseProcess._bootstrap at 0x7febd6287740>
└
File "/usr/local/lib/python3.11/multiprocessing/process.py", line 314, in _bootstrap
self.run()
│ └ <function BaseProcess.run at 0x7febd6286ca0>
└
File "/usr/local/lib/python3.11/multiprocessing/process.py", line 108, in run
self._target(*self._args, **self._kwargs)
│ │ │ │ │ └ {'config': <uvicorn.config.Config object at 0x7febd5f1ad50>, 'target': <bound method Process.target of <uvicorn.supervisors.m...
│ │ │ │ └
│ │ │ └ ()
│ │ └
│ └ <function subprocess_started at 0x7febd542d440>
└
File "/usr/local/lib/python3.11/site-packages/uvicorn/_subprocess.py", line 80, in subprocess_started
target(sockets=sockets)
│ └ [<socket.socket fd=3, family=2, type=1, proto=0, laddr=('0.0.0.0', 8080)>]
└ <bound method Process.target of <uvicorn.supervisors.multiprocess.Process object at 0x7febd5359c50>>
File "/usr/local/lib/python3.11/site-packages/uvicorn/supervisors/multiprocess.py", line 64, in target
return self.real_target(sockets)
│ │ └ [<socket.socket fd=3, family=2, type=1, proto=0, laddr=('0.0.0.0', 8080)>]
│ └ <bound method Server.run of <uvicorn.server.Server object at 0x7febd5359d90>>
└ <uvicorn.supervisors.multiprocess.Process object at 0x7febd5359c50>
File "/usr/local/lib/python3.11/site-packages/uvicorn/server.py", line 67, in run
return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory())
│ │ │ │ │ │ └ <function Config.get_loop_factory at 0x7febd55bc400>
│ │ │ │ │ └ <uvicorn.config.Config object at 0x7febd5f1ad50>
│ │ │ │ └ <uvicorn.server.Server object at 0x7febd5359d90>
│ │ │ └ [<socket.socket fd=3, family=2, type=1, proto=0, laddr=('0.0.0.0', 8080)>]
│ │ └ <function Server.serve at 0x7febd542c220>
│ └ <uvicorn.server.Server object at 0x7febd5359d90>
└ <function asyncio_run at 0x7febd5568a40>
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 0x7febd52b7b50>
│ └ <function Runner.run at 0x7febd57d94e0>
└ <asyncio.runners.Runner object at 0x7febd5359910>
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:71> wai...
│ │ └ <cyfunction Loop.run_until_complete at 0x7febd507a980>
│ └ <uvloop.Loop running=True closed=False debug=False>
└ <asyncio.runners.Runner object at 0x7febd5359910>
File "/app/backend/open_webui/main.py", line 1868, in process_chat
return await process_chat_response(response, ctx)
│ │ └ {'request': <starlette.requests.Request object at 0x7fea3e9ba710>, 'form_data': {'stream': True, 'model': 'gpt-5.2', 'message...
│ └ <starlette.responses.StreamingResponse object at 0x7fea3dba3e50>
└ <function process_chat_response at 0x7fea4723a840>
File "/app/backend/open_webui/utils/middleware.py", line 4730, in process_chat_response
return await streaming_chat_response_handler(response, ctx)
│ │ └ {'request': <starlette.requests.Request object at 0x7fea3e9ba710>, 'form_data': {'stream': True, 'model': 'gpt-5.2', 'message...
│ └ <starlette.responses.StreamingResponse object at 0x7fea3dba3e50>
└ <function streaming_chat_response_handler at 0x7fea4723a7a0>
File "/app/backend/open_webui/utils/middleware.py", line 4678, in streaming_chat_response_handler
return await response_handler(response, events)
│ │ └ []
│ └ <starlette.responses.StreamingResponse object at 0x7fea3dba3e50>
└ <function streaming_chat_response_handler..response_handler at 0x7fea3e812d40>
File "/app/backend/open_webui/utils/middleware.py", line 4659, in response_handler
await background_tasks_handler(ctx)
│ └ {'request': <starlette.requests.Request object at 0x7fea3e9ba710>, 'form_data': {'stream': True, 'model': 'gpt-5.2', 'message...
└ <function background_tasks_handler at 0x7fea4723a660>
File "/app/backend/open_webui/utils/middleware.py", line 2836, in background_tasks_handler
res = await generate_follow_ups(
└ <function generate_follow_ups at 0x7fea4972db20>
File "/app/backend/open_webui/utils/chat.py", line 188, in generate_chat_completion
raise Exception("Model not found")
Exception: Model not found
Additional Information
Root Cause Analysis:
This issue is caused by a race condition in RedisDict.set at backend/open_webui/socket/utils.py. This is a severe problem that becomes visible only in deployments with high load, many replicas, and a large number of activity and models.
Any time a pod refreshes the model list (via /api/models, admin changes, get_all_models, or cache refresh), it executes request.app.state.MODELS.set(models_dict).
RedisDict.set uses a Redis pipeline:
Redis pipelines are not atomic. There is a moment between DELETE and HSET where the hash does not exist.
During this small window, any pod checking for a model (such as in generate_follow_ups or generate_chat_completion) may see the hash as empty, causing “model not found”.
I am not a Redis expert, so the suggested fix courtesy of Claude should absolutely be taken with a grain of salt and could be completely useless. The exact implementation of the fix should be reviewed and validated by someone with actual Redis expertise:
@tjbck commented on GitHub (Mar 22, 2026):
Addressed in dev.