[PR #24170] [CLOSED] fix(chat): recover from malformed history.currentId instead of infinite loading #98571

Closed
opened 2026-05-16 01:22:42 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/open-webui/open-webui/pull/24170
Author: @SymbolStar
Created: 4/27/2026
Status: Closed

Base: mainHead: fix/chat-history-malformed-message-recovery


📝 Commits (1)

  • 65ba772 fix(chat): recover from malformed history.currentId instead of infinite loading

📊 Changes

2 files changed (+67 additions, -0 deletions)

View changed files

📝 src/lib/components/chat/Chat.svelte (+21 -0)
📝 src/lib/utils/index.ts (+46 -0)

📄 Description

Summary

Fixes #24157 — when an upstream OpenAI-compatible provider returns a safety-rejection or content-filter response that lacks the standard message schema (no role / childrenIds), the malformed object can end up persisted in chat.history.messages and assigned as history.currentId. The chat view then locks up on an infinite Loading spinner because downstream renderers rely on those fields.

Approach

Add two small helpers in src/lib/utils/index.ts:

  • isRenderableMessage(message) — predicate that requires both role (string) and childrenIds (array) before treating a node as safe to render.
  • findLastRenderableAncestor(history, startId) — walks the parent chain (cycle-safe via Set) and returns the first renderable ancestor, or null if none exists.

Wire them into Chat.svelte#loadChat: right after the chat content is loaded, if history.currentId points at a non-renderable message, log a console warning and reset history.currentId to the last valid ancestor (or null if no valid ancestor exists). This lets the chat recover automatically and the malformed node is preserved in history.messages for diagnostics.

Behavior

Scenario Before After
currentId points at valid message renders normally renders normally (no change)
currentId points at malformed node, valid ancestor exists infinite Loading recovers to ancestor + console warning
currentId points at malformed node, no valid ancestor infinite Loading empty chat (renders nothing) + console warning
history.messages empty / no currentId as before as before (no change)

The malformed message is not deleted — preserved for forensics. Upstream provider responsibility (returning valid OpenAI-compatible JSON) is unchanged; this just makes Open WebUI defensively robust against bad shapes.

Verification

  • prettier --check:
  • npm run check (svelte-check): no new errors introduced (existing 9361 errors are preexisting in main)
  • Unit tests: there is no existing utils/index.test.ts to extend; happy to add one if maintainers prefer.

Refs


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/open-webui/open-webui/pull/24170 **Author:** [@SymbolStar](https://github.com/SymbolStar) **Created:** 4/27/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/chat-history-malformed-message-recovery` --- ### 📝 Commits (1) - [`65ba772`](https://github.com/open-webui/open-webui/commit/65ba7729a085e39e64f2bc4cbc575d4a35255b35) fix(chat): recover from malformed history.currentId instead of infinite loading ### 📊 Changes **2 files changed** (+67 additions, -0 deletions) <details> <summary>View changed files</summary> 📝 `src/lib/components/chat/Chat.svelte` (+21 -0) 📝 `src/lib/utils/index.ts` (+46 -0) </details> ### 📄 Description ## Summary Fixes #24157 — when an upstream OpenAI-compatible provider returns a safety-rejection or content-filter response that lacks the standard message schema (no `role` / `childrenIds`), the malformed object can end up persisted in `chat.history.messages` and assigned as `history.currentId`. The chat view then locks up on an **infinite Loading spinner** because downstream renderers rely on those fields. ## Approach Add two small helpers in `src/lib/utils/index.ts`: - **`isRenderableMessage(message)`** — predicate that requires both `role` (string) and `childrenIds` (array) before treating a node as safe to render. - **`findLastRenderableAncestor(history, startId)`** — walks the parent chain (cycle-safe via `Set`) and returns the first renderable ancestor, or `null` if none exists. Wire them into `Chat.svelte#loadChat`: right after the chat content is loaded, if `history.currentId` points at a non-renderable message, log a console warning and reset `history.currentId` to the last valid ancestor (or `null` if no valid ancestor exists). This lets the chat recover automatically and the malformed node is **preserved in `history.messages`** for diagnostics. ## Behavior | Scenario | Before | After | |---|---|---| | `currentId` points at valid message | renders normally | renders normally (no change) | | `currentId` points at malformed node, valid ancestor exists | infinite Loading | recovers to ancestor + console warning | | `currentId` points at malformed node, no valid ancestor | infinite Loading | empty chat (renders nothing) + console warning | | `history.messages` empty / no `currentId` | as before | as before (no change) | The malformed message is **not deleted** — preserved for forensics. Upstream provider responsibility (returning valid OpenAI-compatible JSON) is unchanged; this just makes Open WebUI defensively robust against bad shapes. ## Verification - `prettier --check`: ✅ - `npm run check` (svelte-check): ✅ no new errors introduced (existing 9361 errors are preexisting in `main`) - Unit tests: there is no existing `utils/index.test.ts` to extend; happy to add one if maintainers prefer. ## Refs - Closes #24157 --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-05-16 01:22:42 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#98571