From 601e0e4345f2a9f1fd114668ae4e8ef8e5f96603 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 14 Sep 2026 03:28:54 +0200 Subject: [PATCH] fix: stop tracking tasks under an empty item id (#29980) An authenticated socket client can grow Open WebUI's memory without bound by sending ydoc updates for an empty document id. create_task files every task under item_tasks[id] whatever the id, while cleanup_task removes it only for a truthy id, so each update leaves a uuid behind for the process lifetime. normalize_document_id passes an empty id through, and such an id also skips the note access check. create_task now files the task only when an id is provided, which is what its own comment already described and what the rest of the file does: redis_save_task and redis_cleanup_task both guard on a truthy item id, and stop_task normalizes a falsy one away. Nothing is filed, so nothing leaks, and cleanup_task's existing guard correctly no-ops. This also settles a disagreement between the two backends. For an empty id, list_task_ids_by_item_id, has_active_tasks and stop_item_tasks answered one way with Redis and another without it; they now match. The visible consequence is that an instance without Redis no longer cancels a pending save for an empty document id, which is how Redis instances already behaved. Measured over 300 calls with an empty id: 300 stale entries before, none after. Behaviour for a normal id is unchanged, including ordering, cancellation and key removal when the last task finishes. --- backend/open_webui/tasks.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/backend/open_webui/tasks.py b/backend/open_webui/tasks.py index 6a1d6df84f..322cd32e60 100644 --- a/backend/open_webui/tasks.py +++ b/backend/open_webui/tasks.py @@ -140,10 +140,11 @@ async def create_task(redis, coroutine, id=None, task_id=None): tasks[task_id] = task # If an ID is provided, associate the task with that ID - if item_tasks.get(id): - item_tasks[id].append(task_id) - else: - item_tasks[id] = [task_id] + if id: + if item_tasks.get(id): + item_tasks[id].append(task_id) + else: + item_tasks[id] = [task_id] if redis: await redis_save_task(redis, task_id, id)