mirror of
https://github.com/open-webui/open-webui.git
synced 2026-05-06 02:48:13 -05:00
[GH-ISSUE #21347] bug: v0.8.0 Analytics: Inconsistent token tracking + PostgreSQL crash on per-model view #58115
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 @smorello87 on GitHub (Feb 13, 2026).
Original GitHub issue: https://github.com/open-webui/open-webui/issues/21347
Bug Description
Two related issues with the new Analytics feature in v0.8.0 when using PostgreSQL and OpenAI-compatible providers (OpenRouter).
Bug 1: Inconsistent token counts in streaming responses
Severity: High — analytics token data is unreliable
Token usage is recorded for some messages but not others, seemingly at random. The behavior appears timing-dependent rather than model- or user-specific.
Root cause: Race condition in the frontend streaming handler. OpenRouter (and other OpenAI-compatible providers) send usage data in the last SSE chunk before
[DONE]. However,chatCompletedHandlersometimes fires before the usage chunk is processed, resulting in the message being saved with 0 tokens.Evidence:
openAIStreamToIteratorcorrectly parsesparsedData.usagefrom SSE chunksPossibly related: #15850 ("missing tokens when streaming on fast inference providers")
Bug 2: Per-model analytics crashes on PostgreSQL
Severity: Medium — per-model analytics page returns HTTP 500
GET /api/v1/analytics/models/{model_id}/overview?days=30returns 500.Error:
Root cause:
get_chat_ids_by_model_id()inchat_messages.py:298usesSELECT DISTINCT chat_id ... ORDER BY created_at DESC. PostgreSQL requires thatORDER BYcolumns appear in theSELECTlist when usingDISTINCT. SQLite does not have this restriction.Fix: Either add
created_atto the SELECT list and use a subquery, or useGROUP BYinstead ofDISTINCT.Environment
Steps to Reproduce
Bug 1 (inconsistent tokens):
Bug 2 (PostgreSQL crash):
Expected Behavior
Additional Context
The main analytics dashboard endpoints (
/analytics/summary,/analytics/users,/analytics/models,/analytics/tokens,/analytics/daily) all return 200 OK. Only the per-model overview endpoint crashes.OpenRouter has deprecated
stream_options.include_usage— usage is now always included in every streaming response regardless of that flag. So the data is available; it's just not being reliably captured.@pr-validator-bot commented on GitHub (Feb 13, 2026):
⚠️ Missing Issue Title Prefix
@smorello87, your issue title is missing a prefix (e.g.,
bug:,feat:,docs:).Please update your issue title to include one of the following prefixes:
Example:
bug: Login fails when using special characters in password@smorello87 commented on GitHub (Feb 13, 2026):
Update: Root Cause Identified for Bug 1 (Inconsistent Token Tracking)
After investigating the database directly, I found the actual root cause. It's not a race condition — it's a key name mismatch between what gets saved and what analytics queries read.
The Problem
What gets saved: OpenRouter (and other OpenAI-compatible APIs) return usage as
prompt_tokens/completion_tokens. This is what gets stored in thechat_message.usageJSON column.What analytics queries read: The analytics methods in
chat_messages.py(get_token_usage_by_model,get_token_usage_by_user) query forinput_tokens/output_tokens:The
normalize_usagefunction (utils/response.py) is supposed to addinput_tokens/output_tokensalongsideprompt_tokens/completion_tokens, but it is inconsistently applied. In our production database: only 14 out of 107 messages had the normalized keys.Evidence
Why
normalize_usageIs Inconsistently AppliedLooking at
middleware.py, the streaming handler does callnormalize_usage()at line ~3405-3410:But there appear to be multiple code paths where usage gets saved to the
chat_messagetable, and not all go throughnormalize_usage. TheChatMessage.upsert_messagemethod extracts usage directly from the message data dict without normalization:Suggested Fix
The simplest fix would be to normalize usage in
ChatMessage.upsert_message()before saving, ensuring all code paths produce consistent keys:Alternatively, the analytics queries could fall back to
prompt_tokens/completion_tokenswheninput_tokens/output_tokensare not present.Workaround
We applied this SQL fix to normalize existing records:
This needs to be re-run periodically until the upstream fix is applied.
Environment
@Classic298 commented on GitHub (Feb 13, 2026):
Are you sure your chat message table database upgrade ran through completely and without issues - and you actually let it finish?
@Classic298 commented on GitHub (Feb 13, 2026):
Fixed by: https://github.com/open-webui/open-webui/pull/21351
@smorello87 commented on GitHub (Feb 13, 2026):
@Classic298 Thanks for looking into this and for the quick PostgreSQL fix in #21351!
To answer your question — yes, the migration completed successfully. The
chat_messagetable is fully populated with all records and usage data. We verified this by querying the table directly:usageJSON populatedprompt_tokens/completion_tokens(the data is there)input_tokens/output_tokens(which is what the analytics queries read)So the migration itself is fine — the issue (Bug 2) is specifically that the
normalize_usage()function isn't consistently adding theinput_tokens/output_tokenskeys before the data gets saved tochat_message.usage. The analytics queries inget_token_usage_by_modelandget_token_usage_by_useronly look forinput_tokens/output_tokens, so records that only have the OpenAI-format keys (prompt_tokens/completion_tokens) are invisible to the dashboard.Thanks again for the fast turnaround on the PostgreSQL fix!
@Classic298 commented on GitHub (Feb 13, 2026):
one bug is fixed in dev now.
@xec-abailey commented on GitHub (Feb 13, 2026):
In case others are hitting this issue, will this fix prevent all token counts from showing up as 0 or is there additional configuration I'm missing to pull that through?
@smorello87 commented on GitHub (Feb 13, 2026):
Hi, the workaround described above did fix it for our instance but we had to set up a cron job to run it every few hours. hoping for a permanent fix in the next release
@Joly0 commented on GitHub (Feb 18, 2026):
Hey guys, i dont want to hijack this issue, but i guess i have a very similar issue, that the "User activity" data regarding the tokens is very inconsistent, not only for postgres, but for me aswell with sqlite as the database. A lot of users show token usage of 0, while their message count does 100% show that this cant be true.
What i also noticed is that the token count for "Model usage" seems to be incorrect aswell and additionally, when i want to check per model usage, the overview and the chats tab are completly empty, even for models that have milions of token usage:
(Also would be cool if the name of the model wasnt cut-off like that)
@Classic298 commented on GitHub (Feb 18, 2026):
probably your migration didnt fully finish and not all data was migrated in your case
Overview is empty because there is no feedback given
if the chats tab is empty, then you should look into what data is stored in your table and or if you see any errors.
@smorello87 commented on GitHub (Feb 18, 2026):
Update: Bug 1 (usage key mismatch) is NOT fixed in v0.8.3
We upgraded to v0.8.3 today and confirmed that Bug 2 (PostgreSQL DISTINCT) is fixed — thank you!
However, Bug 2 (usage key name mismatch) persists in v0.8.3. After upgrading, all new messages still save usage with only
prompt_tokens/completion_tokens— theinput_tokens/output_tokenskeys that analytics queries need are still missing.Root cause:
normalize_usage()is called in the streaming middleware (middleware.py:3483) and sets a localusagevariable, but the actual database write goes through a different path:Chats.upsert_message_to_chat_by_id_and_message_id()merges the message intohistory["messages"]chat_messageviaChatMessages.upsert_message(data=history["messages"][message_id])upsert_message()extractsdata.get("usage")— which is the raw usage from the history dict, not the normalized versionThe normalized
usagevariable frommiddleware.py:3483is emitted to the frontend via WebSocket (chat:completionevent) but never makes it into the history dict that gets passed toChatMessages.upsert_message().Suggested fix: Add normalization in
ChatMessages.upsert_message()(inmodels/chat_messages.py) right before saving — this is the bottleneck where all code paths converge:This needs to be added in both the update and insert branches of
upsert_message().We've applied this as a build-time patch on our deployment and confirmed it works — new messages now have both key formats and analytics displays correctly.
@Joly0 — this is likely the same issue you're seeing with inconsistent token data. The migration itself is fine; it's that new messages are being saved with the wrong key names. If you can run SQL against your database, this one-liner will fix existing records:
@Classic298 commented on GitHub (Feb 19, 2026):
Thats correct, bug 1 is not fixed yet.
And there's already a pr here in case you didnt see it directly above your comment. https://github.com/open-webui/open-webui/pull/21542
@smorello87 commented on GitHub (Feb 19, 2026):
Thank you, I had missed that indeed.
@tjbck commented on GitHub (Feb 23, 2026):
#21675
@Podden commented on GitHub (Mar 1, 2026):
Do you track Cache usage as well? I have an Anthropic pipe and I want to make it compatible with your analytics. Currently with "Usage" active on a model, I'm just returning normal anthropic Message api data, but this would not be compatible am I right?
Whats the correct format to get picked up by analytics?
@Doan-IT commented on GitHub (Mar 31, 2026):
Hello, is anyone following this issue?
@smorello87 commented on GitHub (Apr 1, 2026):
For what it's worth it, we're still applying our patch to make it work.
On Tue, Mar 31, 2026 at 5:15 AM Doan-IT @.***> wrote:
--
Stefano Morello, Ph.D. // www.stefanomorello.com
Assistant Director for Digital Projects // American Social History Project
/ Center for Media and Learning https://ashp.cuny.edu/ // The Graduate
Center, CUNY
Founding Editor // JAm It! (Journal of American Studies in Italy)
https://www.ojs.unito.it/index.php/jamit/
Executive Council Representative // Association for Computers and
the Humanities
Executive Committee Representative // Italian American Studies Association
@Classic298 commented on GitHub (Apr 1, 2026):
@smorello87 feel free to PR
@garrettashcroft1231-max commented on GitHub (Apr 1, 2026):
Yes, this issue is still reproducible on the latest version
On Wed, Apr 1, 2026, 8:37 AM Classic298 @.***> wrote:
@Classic298 commented on GitHub (Apr 1, 2026):
@garrettashcroft1231-max thanks we know. feel free to PR
@smorello87 commented on GitHub (Apr 1, 2026):
PR submitted: #23322