[PR #21657] [CLOSED] fix: reset generation state and message queue when switching chats [PoC] #97224

Closed
opened 2026-05-15 23:38:59 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/open-webui/open-webui/pull/21657
Author: @silentoplayz
Created: 2/20/2026
Status: Closed

Base: devHead: fix/chat-state-isolation


📝 Commits (4)

  • 46cd933 fix(chat): reset generation state and message queue when switching chats
  • fba6ecb fix(chat): guard completion state assignments against chat switching
  • f94c7df fix(chat): save messageQueue to sessionStorage when background chat finishes
  • 1c65bd2 fix(chat): guard taskIds and messageQueue execution strictly to active chat

📊 Changes

1 file changed (+41 additions, -21 deletions)

View changed files

📝 src/lib/components/chat/Chat.svelte (+41 -21)

📄 Description

Pull Request Checklist

Note to first-time contributors: Please open a discussion post in Discussions to discuss your idea/fix with the community before creating a pull request, and describe your changes before submitting a pull request.

This is to ensure large feature PRs are discussed with the community first, before starting work on it. If the community does not want this feature or it is not relevant for Open WebUI as a project, it can be identified in the discussion before working on the feature and submitting the PR.

Before submitting, make sure you've checked the following:

  • Target branch: Verify that the pull request targets the dev branch. PRs targeting main will be immediately closed.
  • Description: Provide a concise description of the changes made in this pull request down below.
  • Changelog: Ensure a changelog entry following the format of Keep a Changelog is added at the bottom of the PR description.
  • Documentation: Add docs in Open WebUI Docs Repository. Document user-facing behavior, environment variables, public APIs/interfaces, or deployment steps.
  • Dependencies: Are there any new or upgraded dependencies? If so, explain why, update the changelog/docs, and include any compatibility notes. Actually run the code/function that uses updated library to ensure it doesn't crash.
  • Testing: Perform manual tests to verify the implemented fix/feature works as intended AND does not break any other functionality. Include reproducible steps to demonstrate the issue before the fix. Test edge cases (URL encoding, HTML entities, types). Take this as an opportunity to make screenshots of the feature/fix and include them in the PR description.
  • Agentic AI Code: Confirm this Pull Request is not written by any AI Agent or has at least gone through additional human review AND manual testing. If any AI Agent is the co-author of this PR, it may lead to immediate closure of the PR.
  • Code review: Have you performed a self-review of your code, addressing any coding standard issues and ensuring adherence to the project's coding standards?
  • Design & Architecture: Prefer smart defaults over adding new settings; use local state for ephemeral UI logic. Open a Discussion for major architectural or UX changes.
  • Git Hygiene: Keep PRs atomic (one logical change). Clean up commits and rebase on dev to ensure no unrelated commits (e.g. from main) are included. Push updates to the existing PR branch instead of closing and reopening.
  • Title Prefix: To clearly categorize this pull request, prefix the pull request title using one of the following:
    • BREAKING CHANGE: Significant changes that may affect compatibility
    • build: Changes that affect the build system or external dependencies
    • ci: Changes to our continuous integration processes or workflows
    • chore: Refactor, cleanup, or other non-functional code changes
    • docs: Documentation update or addition
    • feat: Introduces a new feature or enhancement to the codebase
    • fix: Bug fix or error correction
    • i18n: Internationalization or localization changes
    • perf: Performance improvement
    • refactor: Code restructuring for better maintainability, readability, or scalability
    • style: Changes that do not affect the meaning of the code (white space, formatting, missing semi-colons, etc.)
    • test: Adding missing tests or correcting existing tests
    • WIP: Work in progress, a temporary label for incomplete or ongoing work

Changelog Entry

Description

  • Fixed chat state leakage across navigation. When switching chats or creating a new chat while a background generation is occurring, the Svelte component state was not properly isolated, causing issues like misplaced messages and queued prompt processing executing in incorrect contexts. The fixes target Chat.svelte to thoroughly reset local state, handle background API resolution by applying active chat ID guards ($chatId === _chatId), and smoothly persist background Queues into sessionStorage for seamless task resumption upon revisiting the older chat.

Added

  • Saves pending messageQueue array into sessionStorage for background chats when generations finish, ensuring their messages are preserved and automatically executed upon reloading the chat.

Changed

  • Updates Chat.svelte loadChat and initNewChat methods to thoroughly explicitly flush state variables (messageQueue, taskIds, generationController, generating).
  • Modifies generation Promise resolution logic in sendMessageSocket to verify that the target _chatId is identical to $chatId prior to applying any done, history, or taskId state updates, protecting the isolated active chat window.
  • Guards Svelte completion execution checks in chatCompletedHandler with $chatId === _chatId to prevent background generation logic from indiscriminately nullifying taskIds of a separate active chat.

Fixed

  • Fixed TypeError: can't access property "parentId" when clicking the Stop Generation button after navigating to a new chat.

  • Prevented new messages from getting queued in a newly created chat if the previous chat was still generating.

  • Background generations bleeding into and altering new chat sessions.

  • Stop button state incorrectly flagging responses in the wrong active chat.

  • Active taskIds accidentally deleting and halting queue sequences due to background chatCompletedHandler invocations.

  • "Queued" messages silently failing to resolve when Svelte fires the chat completed event for an unfocused component.

  • This PR resolves the following error(s) that were previously thrown in the browser console (Firefox):

Uncaught (in promise) TypeError: can't access property "parentId", u is undefined
    ua Chat.svelte:2225
    children MessageInput.svelte:1737
    s events.js:61
    Mt shared.js:44
    s events.js:60
Chat.svelte:2225:8
    ua Chat.svelte:2225
    InterpretGeneratorResume self-hosted:1312
    AsyncFunctionNext self-hosted:780
    (Async: async)
    children MessageInput.svelte:1737
    s events.js:61
    Mt shared.js:44
    s events.js:60

&

Uncaught (in promise) TypeError: can't access property "parentId", responseMessage is undefined
    stopResponse Chat.svelte:2225
    children MessageInput.svelte:1737
    target_handler events.js:61
    without_reactive_context shared.js:44
    target_handler events.js:60
    create_event events.js:79
    event events.js:113
    children MessageInput.svelte:3030
    snippet2 snippet.js:53
    slot slot.js:28
    Tooltip Tooltip.svelte:117
    element svelte-element.js:119
    ensure branches.js:166
    update_reaction runtime.js:297
    update_effect runtime.js:477
    create_effect effects.js:126
    branch effects.js:392
    ensure branches.js:166
    element svelte-element.js:69
    update_reaction runtime.js:297
    update_effect runtime.js:477
    create_effect effects.js:126
    block effects.js:380
    element svelte-element.js:59
    Tooltip Tooltip.svelte:102
    effect2 hmr.js:47
    update_reaction runtime.js:297
    update_effect runtime.js:477
    create_effect effects.js:126
    branch effects.js:392
    wrapper hmr.js:38
    update_reaction runtime.js:297
    update_effect runtime.js:477
    create_effect effects.js:126
    block effects.js:380
Chat.svelte:2225:8
    stopResponse Chat.svelte:2225
    AsyncFunctionNext self-hosted:780
    (Async: async)
    children MessageInput.svelte:1737
    target_handler events.js:61
    without_reactive_context shared.js:44
    target_handler events.js:60
    (Async: EventListener.handleEvent)
    create_event events.js:79
    event events.js:113
    children MessageInput.svelte:3030
    snippet2 snippet.js:53
    slot slot.js:28
    Tooltip Tooltip.svelte:117
    element svelte-element.js:119
    ensure branches.js:166
    update_reaction runtime.js:297
    update_effect runtime.js:477
    create_effect effects.js:126
    branch effects.js:392
    ensure branches.js:166
    element svelte-element.js:69
    update_reaction runtime.js:297
    update_effect runtime.js:477
    create_effect effects.js:126
    block effects.js:380
    element svelte-element.js:59
    Tooltip Tooltip.svelte:102
    effect2 hmr.js:47
    update_reaction runtime.js:297
    update_effect runtime.js:477
    create_effect effects.js:126
    branch effects.js:392
    wrapper hmr.js:38
    update_reaction runtime.js:297
    update_effect runtime.js:477
    create_effect effects.js:126
    block effects.js:380

Additional Information

Context & Reasoning for PR Changes:

The core issue this PR addresses is State Leakage between active and background chat domains. Open WebUI's frontend architecture essentially relies on a singleton-esque component state for the currently active tab window. Variables like $chatId, history, taskIds, and messageQueue are inherently bound to the active user session.

When a user triggers a message generation (e.g., in "Chat A") and quickly switches to "Chat B" or initiates a "New Chat", the original generateOpenAIChatCompletion API stream resolves in the background. Because Svelte triggers the corresponding .then() and .catch() blocks in the same component module silently, it was unknowingly dropping the completed variables into Chat B!

This led to a series of escalating edge cases, which this PR fixes anatomically:

  1. fix(chat): reset generation state and message queue when switching chats

    • Why/Reasoning: When you open an existing chat (loadChat) or a new one (initNewChat), Svelte retains the previous variables for taskIds, messageQueue, and generating. This resulted in newly opened chats falsely displaying a "Stop" button and thinking they were still waiting for a generation to finish.
    • How: We explicitly zero-out these variables during the load/init routines so new chat sessions are always guaranteed a clean slate.
  2. fix(chat): guard completion state assignments against chat switching

    • Why/Reasoning: As mentioned, if Chat A's API hit finishes while Chat B is being viewed, the promise resolver evaluates the response and directly updates history and taskIds. This injected Chat A's message completion metadata into Chat B's history object.
    • How: We capture the initiating chat ID (_chatId) at the start of sendMessageSocket and wrap the resolution and error blocks inside if (_chatId === $chatId). This ensures that background API completions gracefully abort UI state mutations if you've already navigated away.
  3. fix(chat): save messageQueue to sessionStorage when background chat finishes

    • Why/Reasoning: Users can queue prompts using Shift+Enter. If task generation is pending when you submit, the prompts go into messageQueue. When the background chat finally completes, chatCompletedHandler normally clears the active task and submits the queue. However, if the user had navigated to Chat B, Svelte has no way to formulate a headless submitPrompt background execution payload since the component state (like file attachments and conversation context) has already been swapped out for Chat B. This causes the queue to get stuck or misfire.
    • How: We updated chatCompletedHandler so that if $chatId !== _chatId (meaning we're resolving a background chat), Svelte isolates and stashes the queue natively into sessionStorage (specifically under chat-queue-${_chatId}). When the user eventually returns to Chat A, the navigateHandler pulls it back out and automatically initiates the queued execution with the correct refreshed scope.
  4. fix(chat): guard taskIds and messageQueue execution strictly to active chat

    • Why/Reasoning: During testing of the queue recovery functionality, we discovered a cross-talk bug. When chatCompletedHandler fired for background Chat A, it was executing taskIds = null; unconditionally. This would accidentally delete the active taskIds of Chat B (your current window!), causing any queued sequences in your active tab to drop and fail.
    • How: We walled off the taskIds clearance and messageQueue direct execution blocks inside an identity check if ($chatId === _chatId). This ensures background chats can't break your actively focused work execution.

Contributor License Agreement

By submitting this pull request, I confirm that I have read and fully agree to the Contributor License Agreement (CLA), and I am providing my contributions under its terms.

Note

Deleting the CLA section will lead to immediate closure of your PR and it will not be merged in.


🔄 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/21657 **Author:** [@silentoplayz](https://github.com/silentoplayz) **Created:** 2/20/2026 **Status:** ❌ Closed **Base:** `dev` ← **Head:** `fix/chat-state-isolation` --- ### 📝 Commits (4) - [`46cd933`](https://github.com/open-webui/open-webui/commit/46cd9335483e7929f1e5c6d4319ba91115b23479) fix(chat): reset generation state and message queue when switching chats - [`fba6ecb`](https://github.com/open-webui/open-webui/commit/fba6ecb42027e7e69a2924f5d1c9da701b394303) fix(chat): guard completion state assignments against chat switching - [`f94c7df`](https://github.com/open-webui/open-webui/commit/f94c7dfbfc3cf677b50ca99740eb72ed65ea1106) fix(chat): save messageQueue to sessionStorage when background chat finishes - [`1c65bd2`](https://github.com/open-webui/open-webui/commit/1c65bd28de3f3d95a2e1afa34775b4687cee18e9) fix(chat): guard taskIds and messageQueue execution strictly to active chat ### 📊 Changes **1 file changed** (+41 additions, -21 deletions) <details> <summary>View changed files</summary> 📝 `src/lib/components/chat/Chat.svelte` (+41 -21) </details> ### 📄 Description <!-- ⚠️ CRITICAL CHECKS FOR CONTRIBUTORS (READ, DON'T DELETE) ⚠️ 1. Target the `dev` branch. PRs targeting `main` will be automatically closed. 2. Do NOT delete the CLA section at the bottom. It is required for the bot to accept your PR. --> # Pull Request Checklist ### Note to first-time contributors: Please open a discussion post in [Discussions](https://github.com/open-webui/open-webui/discussions) to discuss your idea/fix with the community before creating a pull request, and describe your changes before submitting a pull request. This is to ensure large feature PRs are discussed with the community first, before starting work on it. If the community does not want this feature or it is not relevant for Open WebUI as a project, it can be identified in the discussion before working on the feature and submitting the PR. **Before submitting, make sure you've checked the following:** - [x] **Target branch:** Verify that the pull request targets the `dev` branch. **PRs targeting `main` will be immediately closed.** - [x] **Description:** Provide a concise description of the changes made in this pull request down below. - [x] **Changelog:** Ensure a changelog entry following the format of [Keep a Changelog](https://keepachangelog.com/) is added at the bottom of the PR description. - [x] **Documentation:** Add docs in [Open WebUI Docs Repository](https://github.com/open-webui/docs). Document user-facing behavior, environment variables, public APIs/interfaces, or deployment steps. - [x] **Dependencies:** Are there any new or upgraded dependencies? If so, explain why, update the changelog/docs, and include any compatibility notes. Actually run the code/function that uses updated library to ensure it doesn't crash. - [x] **Testing:** Perform manual tests to **verify the implemented fix/feature works as intended AND does not break any other functionality**. Include reproducible steps to demonstrate the issue before the fix. Test edge cases (URL encoding, HTML entities, types). Take this as an opportunity to **make screenshots of the feature/fix and include them in the PR description**. - [x] **Agentic AI Code:** Confirm this Pull Request is **not written by any AI Agent** or has at least **gone through additional human review AND manual testing**. If any AI Agent is the co-author of this PR, it may lead to immediate closure of the PR. - [x] **Code review:** Have you performed a self-review of your code, addressing any coding standard issues and ensuring adherence to the project's coding standards? - [x] **Design & Architecture:** Prefer smart defaults over adding new settings; use local state for ephemeral UI logic. Open a Discussion for major architectural or UX changes. - [x] **Git Hygiene:** Keep PRs atomic (one logical change). Clean up commits and rebase on `dev` to ensure no unrelated commits (e.g. from `main`) are included. Push updates to the existing PR branch instead of closing and reopening. - [x] **Title Prefix:** To clearly categorize this pull request, prefix the pull request title using one of the following: - **BREAKING CHANGE**: Significant changes that may affect compatibility - **build**: Changes that affect the build system or external dependencies - **ci**: Changes to our continuous integration processes or workflows - **chore**: Refactor, cleanup, or other non-functional code changes - **docs**: Documentation update or addition - **feat**: Introduces a new feature or enhancement to the codebase - **fix**: Bug fix or error correction - **i18n**: Internationalization or localization changes - **perf**: Performance improvement - **refactor**: Code restructuring for better maintainability, readability, or scalability - **style**: Changes that do not affect the meaning of the code (white space, formatting, missing semi-colons, etc.) - **test**: Adding missing tests or correcting existing tests - **WIP**: Work in progress, a temporary label for incomplete or ongoing work # Changelog Entry ### Description - Fixed chat state leakage across navigation. When switching chats or creating a new chat while a background generation is occurring, the Svelte component state was not properly isolated, causing issues like misplaced messages and queued prompt processing executing in incorrect contexts. The fixes target Chat.svelte to thoroughly reset local state, handle background API resolution by applying active chat ID guards (`$chatId === _chatId`), and smoothly persist background Queues into `sessionStorage` for seamless task resumption upon revisiting the older chat. ### Added - Saves pending `messageQueue` array into `sessionStorage` for background chats when generations finish, ensuring their messages are preserved and automatically executed upon reloading the chat. ### Changed - Updates Chat.svelte `loadChat` and `initNewChat` methods to thoroughly explicitly flush state variables (`messageQueue`, `taskIds`, `generationController`, `generating`). - Modifies generation Promise resolution logic in `sendMessageSocket` to verify that the target `_chatId` is identical to `$chatId` prior to applying any `done`, `history`, or `taskId` state updates, protecting the isolated active chat window. - Guards Svelte completion execution checks in `chatCompletedHandler` with `$chatId === _chatId` to prevent background generation logic from indiscriminately nullifying `taskIds` of a separate active chat. ### Fixed - Fixed `TypeError: can't access property "parentId"` when clicking the Stop Generation button after navigating to a new chat. - Prevented new messages from getting queued in a newly created chat if the previous chat was still generating. - Background generations bleeding into and altering new chat sessions. - Stop button state incorrectly flagging responses in the wrong active chat. - Active taskIds accidentally deleting and halting queue sequences due to background `chatCompletedHandler` invocations. - "Queued" messages silently failing to resolve when Svelte fires the chat completed event for an unfocused component. - This PR resolves the following error(s) that were previously thrown in the browser console (Firefox): ```js Uncaught (in promise) TypeError: can't access property "parentId", u is undefined ua Chat.svelte:2225 children MessageInput.svelte:1737 s events.js:61 Mt shared.js:44 s events.js:60 Chat.svelte:2225:8 ua Chat.svelte:2225 InterpretGeneratorResume self-hosted:1312 AsyncFunctionNext self-hosted:780 (Async: async) children MessageInput.svelte:1737 s events.js:61 Mt shared.js:44 s events.js:60 ``` & ```js Uncaught (in promise) TypeError: can't access property "parentId", responseMessage is undefined stopResponse Chat.svelte:2225 children MessageInput.svelte:1737 target_handler events.js:61 without_reactive_context shared.js:44 target_handler events.js:60 create_event events.js:79 event events.js:113 children MessageInput.svelte:3030 snippet2 snippet.js:53 slot slot.js:28 Tooltip Tooltip.svelte:117 element svelte-element.js:119 ensure branches.js:166 update_reaction runtime.js:297 update_effect runtime.js:477 create_effect effects.js:126 branch effects.js:392 ensure branches.js:166 element svelte-element.js:69 update_reaction runtime.js:297 update_effect runtime.js:477 create_effect effects.js:126 block effects.js:380 element svelte-element.js:59 Tooltip Tooltip.svelte:102 effect2 hmr.js:47 update_reaction runtime.js:297 update_effect runtime.js:477 create_effect effects.js:126 branch effects.js:392 wrapper hmr.js:38 update_reaction runtime.js:297 update_effect runtime.js:477 create_effect effects.js:126 block effects.js:380 Chat.svelte:2225:8 stopResponse Chat.svelte:2225 AsyncFunctionNext self-hosted:780 (Async: async) children MessageInput.svelte:1737 target_handler events.js:61 without_reactive_context shared.js:44 target_handler events.js:60 (Async: EventListener.handleEvent) create_event events.js:79 event events.js:113 children MessageInput.svelte:3030 snippet2 snippet.js:53 slot slot.js:28 Tooltip Tooltip.svelte:117 element svelte-element.js:119 ensure branches.js:166 update_reaction runtime.js:297 update_effect runtime.js:477 create_effect effects.js:126 branch effects.js:392 ensure branches.js:166 element svelte-element.js:69 update_reaction runtime.js:297 update_effect runtime.js:477 create_effect effects.js:126 block effects.js:380 element svelte-element.js:59 Tooltip Tooltip.svelte:102 effect2 hmr.js:47 update_reaction runtime.js:297 update_effect runtime.js:477 create_effect effects.js:126 branch effects.js:392 wrapper hmr.js:38 update_reaction runtime.js:297 update_effect runtime.js:477 create_effect effects.js:126 block effects.js:380 ``` --- ### Additional Information **Context & Reasoning for PR Changes:** The core issue this PR addresses is **State Leakage between active and background chat domains**. Open WebUI's frontend architecture essentially relies on a singleton-esque component state for the currently active tab window. Variables like `$chatId`, `history`, `taskIds`, and `messageQueue` are inherently bound to the *active user session*. When a user triggers a message generation (e.g., in "Chat A") and quickly switches to "Chat B" or initiates a "New Chat", the original `generateOpenAIChatCompletion` API stream resolves in the background. Because Svelte triggers the corresponding `.then()` and `.catch()` blocks in the same component module silently, it was unknowingly dropping the completed variables into Chat B! This led to a series of escalating edge cases, which this PR fixes anatomically: 1. **`fix(chat): reset generation state and message queue when switching chats`** * **Why/Reasoning**: When you open an existing chat (`loadChat`) or a new one (`initNewChat`), Svelte retains the previous variables for `taskIds`, `messageQueue`, and `generating`. This resulted in newly opened chats falsely displaying a "Stop" button and thinking they were still waiting for a generation to finish. * **How**: We explicitly zero-out these variables during the load/init routines so new chat sessions are always guaranteed a clean slate. 2. **`fix(chat): guard completion state assignments against chat switching`** * **Why/Reasoning**: As mentioned, if Chat A's API hit finishes while Chat B is being viewed, the promise resolver evaluates the response and directly updates `history` and `taskIds`. This injected Chat A's message completion metadata into Chat B's history object. * **How**: We capture the initiating chat ID (`_chatId`) at the start of `sendMessageSocket` and wrap the resolution and error blocks inside `if (_chatId === $chatId)`. This ensures that background API completions gracefully abort UI state mutations if you've already navigated away. 3. **`fix(chat): save messageQueue to sessionStorage when background chat finishes`** * **Why/Reasoning**: Users can queue prompts using Shift+Enter. If task generation is pending when you submit, the prompts go into `messageQueue`. When the background chat finally completes, `chatCompletedHandler` normally clears the active task and submits the queue. However, if the user had navigated to Chat B, Svelte has no way to formulate a headless `submitPrompt` background execution payload since the component state (like file attachments and conversation context) has already been swapped out for Chat B. This causes the queue to get stuck or misfire. * **How**: We updated `chatCompletedHandler` so that if `$chatId !== _chatId` (meaning we're resolving a background chat), Svelte isolates and stashes the queue natively into `sessionStorage` (specifically under `chat-queue-${_chatId}`). When the user eventually returns to Chat A, the `navigateHandler` pulls it back out and automatically initiates the queued execution with the correct refreshed scope. 4. **`fix(chat): guard taskIds and messageQueue execution strictly to active chat`** * **Why/Reasoning**: During testing of the queue recovery functionality, we discovered a cross-talk bug. When `chatCompletedHandler` fired for background Chat A, it was executing `taskIds = null;` unconditionally. This would accidentally delete the active `taskIds` of *Chat B* (your current window!), causing any queued sequences in your active tab to drop and fail. * **How**: We walled off the `taskIds` clearance and `messageQueue` direct execution blocks inside an identity check `if ($chatId === _chatId)`. This ensures background chats can't break your actively focused work execution. ### Contributor License Agreement <!-- 🚨 DO NOT DELETE THE TEXT BELOW 🚨 Keep the "Contributor License Agreement" confirmation text intact. Deleting it will trigger the CLA-Bot to INVALIDATE your PR. --> By submitting this pull request, I confirm that I have read and fully agree to the [Contributor License Agreement (CLA)](https://github.com/open-webui/open-webui/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT), and I am providing my contributions under its terms. > [!NOTE] > Deleting the CLA section will lead to immediate closure of your PR and it will not be merged in. --- <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-15 23:38:59 -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#97224