mirror of
https://github.com/open-webui/open-webui.git
synced 2026-05-22 09:31:58 -05:00
[GH-ISSUE #23938] issue: OpenTelemetry callback for webui.users.active.today is async def, causing "coroutine is not iterable" on every export #107108
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 @flobrunner on GitHub (Apr 21, 2026).
Original GitHub issue: https://github.com/open-webui/open-webui/issues/23938
Check Existing Issues
Installation Method
Docker
Open WebUI Version
v0.9.0
Ollama Version (if applicable)
No response
Operating System
Debian 12 & k8s
Browser (if applicable)
No response
Confirmation
README.md.Expected Behavior
The observable gauge
webui.users.active.today(introduced in v0.6.38 via #19236) should export a value each OTEL metrics interval without errors.Actual Behavior
Every export cycle, the OpenTelemetry SDK logs:
Steps to Reproduce
you need to enable OTEL
ENABLE_OTEL = True
Logs & Screenshots
ERROR | opentelemetry.sdk.metrics._internal.instrument:callback:149 -
Callback failed for instrument webui.users.active.today.
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/opentelemetry/sdk/metrics/_internal/instrument.py", line 140, in callback
for api_measurement in callback(callback_options):
TypeError: 'coroutine' object is not iterable
Additional Information
regression from https://github.com/open-webui/open-webui/commit/2716912
observe_users_active_today(options) -> Sequence[metrics.Observation]:
return [metrics.Observation(value=await Users.get_num_users_active_today())]
not validated: claude suggestion
1. Provide a sync variant of the query (cleanest):
def observe_users_active_today(options): return [metrics.Observation(value=Users.get_num_users_active_today_sync())]2. Run the coroutine from the OTEL worker thread:
import asyncio def observe_users_active_today(options): try: loop = asyncio.new_event_loop() val = loop.run_until_complete(Users.get_num_users_active_today()) finally: loop.close() return [metrics.Observation(value=val)]3. Cached value pattern: a background async task updates a module-level counter; the sync callback only reads it.
Option 1 is the most idiomatic. Option 3 is best if the query becomes expensive at scale.
@moritzderallerechte commented on GitHub (Apr 22, 2026):
I have the same issue.
With Version v0.9.0 they updated their Database Abstraction Models to use async.
@dude75 commented on GitHub (Apr 22, 2026):
I have the same issue.
@nwon910 commented on GitHub (Apr 22, 2026):
I have the same issue on v0.9.1 as well
@lebajez commented on GitHub (Apr 22, 2026):
me too
@tjbck commented on GitHub (Apr 24, 2026):
Addressed in dev.
@lebajez commented on GitHub (Apr 25, 2026):
somehow the new update solved this for me