From 1cbfa1be06be67d5a0895cf3f2de1fd9feda91d5 Mon Sep 17 00:00:00 2001 From: PVBLIC Foundation Date: Mon, 11 May 2026 14:20:18 -0700 Subject: [PATCH] fix: handle chat_id=None in event emitter and Drive client Two runtime regressions surfaced from server-to-server callers (tools, automations, llm_council) hitting /api/chat/completions without a chat_id, plus one missed await on the async OAuthSessions API. 1) socket/main.py get_event_emitter - request_info.get('chat_id', '').startswith(...) returned None when chat_id was explicitly None (dict.get default only applies when the key is missing entirely), causing 'NoneType' object has no attribute 'startswith' and a 400 on every tool-driven completion request. - Use `(chat_id or '')` for both startswith calls. 2) utils/middleware.py background_tasks_handler - Same pattern: tightened the chat_id presence check from `'chat_id' in metadata` (False-positive on None values) to `metadata.get('chat_id')`. Also defensively switched two existing `metadata.get('chat_id', '').startswith(...)` checks to use the `or ''` pattern. 3) utils/google_drive_client.py create_drive_client_for_user - OAuthSessions.get_session_by_provider_and_user_id is now async (v0.9.5); the missing await produced "'coroutine' object has no attribute 'id'" when accessing .id on the returned coroutine and prevented all Drive sync runs. Made-with: Cursor --- backend/open_webui/socket/main.py | 9 ++++++--- backend/open_webui/utils/google_drive_client.py | 2 +- backend/open_webui/utils/middleware.py | 12 ++++++------ 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/backend/open_webui/socket/main.py b/backend/open_webui/socket/main.py index d59ff53277..336f61370b 100644 --- a/backend/open_webui/socket/main.py +++ b/backend/open_webui/socket/main.py @@ -898,8 +898,11 @@ async def _make_channel_emitter(request_info): async def get_event_emitter(request_info, update_db=True): - # Channel mode: route pipeline output to channel message updates - if request_info.get('chat_id', '').startswith('channel:'): + # Channel mode: route pipeline output to channel message updates. + # Use `or ''` because callers may pass chat_id=None (server-to-server API + # callers like tools/automations); dict.get default only kicks in when + # the key is missing entirely. + if (request_info.get('chat_id') or '').startswith('channel:'): return await _make_channel_emitter(request_info) async def __event_emitter__(event_data): @@ -917,7 +920,7 @@ async def get_event_emitter(request_info, update_db=True): room=f'user:{user_id}', ) - if update_db and message_id and not request_info.get('chat_id', '').startswith('local:'): + if update_db and message_id and not (request_info.get('chat_id') or '').startswith('local:'): event_type = event_data.get('type') if event_type == 'status': diff --git a/backend/open_webui/utils/google_drive_client.py b/backend/open_webui/utils/google_drive_client.py index 3ca3048bce..931ca9c033 100644 --- a/backend/open_webui/utils/google_drive_client.py +++ b/backend/open_webui/utils/google_drive_client.py @@ -680,7 +680,7 @@ async def create_drive_client_for_user( from open_webui.models.oauth_sessions import OAuthSessions # Get Google OAuth session - oauth_session = OAuthSessions.get_session_by_provider_and_user_id("google", user_id) + oauth_session = await OAuthSessions.get_session_by_provider_and_user_id("google", user_id) if not oauth_session: log.warning(f"No Google OAuth session for user {user_id}") return None diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index d0b6364e2b..3d7aa2b2a1 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -3060,7 +3060,7 @@ async def background_tasks_handler(ctx): messages = [] if ( - 'chat_id' in metadata + metadata.get('chat_id') and not metadata['chat_id'].startswith('local:') and not metadata['chat_id'].startswith('channel:') ): @@ -3143,8 +3143,8 @@ async def background_tasks_handler(ctx): } ) - if not metadata.get('chat_id', '').startswith('local:') and not metadata.get( - 'chat_id', '' + if not (metadata.get('chat_id') or '').startswith('local:') and not ( + metadata.get('chat_id') or '' ).startswith('channel:'): await Chats.upsert_message_to_chat_by_id_and_message_id( metadata['chat_id'], @@ -3157,9 +3157,9 @@ async def background_tasks_handler(ctx): except Exception as e: pass - if not metadata.get('chat_id', '').startswith('local:') and not metadata.get('chat_id', '').startswith( - 'channel:' - ): # Only update titles and tags for non-temp chats + if not (metadata.get('chat_id') or '').startswith('local:') and not ( + metadata.get('chat_id') or '' + ).startswith('channel:'): # Only update titles and tags for non-temp chats if TASKS.TITLE_GENERATION in tasks: user_message = get_last_user_message(messages) if user_message and len(user_message) > 100: