[GH-ISSUE #24550] bug: NoneType object has no attribute 'startswith' — all /api/v1/chat/completions calls return 400 (v0.9.5, direct connections) #123639

Closed
opened 2026-05-21 03:00:26 -05:00 by GiteaMirror · 10 comments
Owner

Originally created by @ThefloorMiner on GitHub (May 10, 2026).
Original GitHub issue: https://github.com/open-webui/open-webui/issues/24550

Bug Description

All chat completion API calls from external clients (CLI tools, IDE extensions, scripts) return HTTP 400 with {"detail": "'NoneType' object has no attribute 'startswith'"} in OpenWebUI 0.9.5.

⚠️ The OpenWebUI web interface works fine — the bug only affects calls to /api/v1/chat/completions made by external API clients using an API key. The web UI sends extra fields (parent_id, chat_id, session_id, etc.) that external clients don't send, which likely triggers a different code path.

The issue affects every configured model and every external API client tested (OpenClaude CLI, VS Code AI extensions).

Environment

  • OpenWebUI version: 0.9.5 (ghcr.io/open-webui/open-webui:latest)
  • Deployment: Docker container
  • Connection mode: Direct connections only — no global Ollama or OpenAI base URLs configured (OLLAMA_BASE_URLS: [], OPENAI_API_BASE_URLS: [], direct.enable: true)
  • Active functions/filters/pipes: None (0 rows in function table)
  • Database: PostgreSQL
  • Auth method: API key (Bearer sk-...)

Steps to Reproduce

curl -s https://<your-instance>/api/v1/chat/completions \
  -H "Authorization: Bearer <api-key>" \
  -H "Content-Type: application/json" \
  -d '{"model":"<any-model-id>","messages":[{"role":"user","content":"hi"}],"max_tokens":5}'

Note: this is a minimal API-style request, as sent by external clients — no chat_id, parent_id, session_id, or other OpenWebUI-specific fields.

Actual Behavior

HTTP 400:

{"detail": "'NoneType' object has no attribute 'startswith'"}

Server log (docker logs):

ERROR | open_webui.main:process_chat:2013 - Error processing chat payload: 'NoneType' object has no attribute 'startswith'
INFO  | ... "POST /api/v1/chat/completions HTTP/1.1" 400

Expected Behavior

HTTP 200 with a streamed or complete chat response — same as what the web UI receives.

Analysis

The error is logged at line 2013 of main.py:

except Exception as e:
    error_detail = e.detail if isinstance(e, HTTPException) else str(e)
    log.error('Error processing chat payload: %s', error_detail)  # line 2013

error_detail = str(e) is 'NoneType' object has no attribute 'startswith' — the original exception is a str.startswith() call on None somewhere in the try block of process_chat.

The crash likely originates in the routing/forwarding stack (model dispatch, pipeline resolution, or direct-connection handling) when a model field or URL is None — a code path only reached when chat_id, parent_id, and session_id are absent (i.e. external API clients).

Additional Notes

  • /api/v1/models works correctly and returns the model list
  • The bug affects all models, including cloud-routed ones — not just locally-served models
  • No custom filters or pipes are active
  • Multiple external clients reproduce the issue; the web UI does not reproduce it
  • The full Python traceback is not logged — only str(e) is captured, which makes root-cause analysis harder

Suggested Improvement

Logging the full traceback in the exception handler would make root-cause analysis much easier:

except Exception as e:
    log.exception('Error processing chat payload')  # logs full traceback
    error_detail = e.detail if isinstance(e, HTTPException) else str(e)
Originally created by @ThefloorMiner on GitHub (May 10, 2026). Original GitHub issue: https://github.com/open-webui/open-webui/issues/24550 ## Bug Description All chat completion API calls from **external clients** (CLI tools, IDE extensions, scripts) return HTTP 400 with `{"detail": "'NoneType' object has no attribute 'startswith'"}` in OpenWebUI 0.9.5. > ⚠️ **The OpenWebUI web interface works fine** — the bug only affects calls to `/api/v1/chat/completions` made by external API clients using an API key. The web UI sends extra fields (`parent_id`, `chat_id`, `session_id`, etc.) that external clients don't send, which likely triggers a different code path. The issue affects every configured model and every external API client tested (OpenClaude CLI, VS Code AI extensions). ## Environment - **OpenWebUI version:** 0.9.5 (`ghcr.io/open-webui/open-webui:latest`) - **Deployment:** Docker container - **Connection mode:** Direct connections only — no global Ollama or OpenAI base URLs configured (`OLLAMA_BASE_URLS: []`, `OPENAI_API_BASE_URLS: []`, `direct.enable: true`) - **Active functions/filters/pipes:** None (0 rows in `function` table) - **Database:** PostgreSQL - **Auth method:** API key (`Bearer sk-...`) ## Steps to Reproduce ```bash curl -s https://<your-instance>/api/v1/chat/completions \ -H "Authorization: Bearer <api-key>" \ -H "Content-Type: application/json" \ -d '{"model":"<any-model-id>","messages":[{"role":"user","content":"hi"}],"max_tokens":5}' ``` > Note: this is a **minimal** API-style request, as sent by external clients — no `chat_id`, `parent_id`, `session_id`, or other OpenWebUI-specific fields. ## Actual Behavior HTTP 400: ```json {"detail": "'NoneType' object has no attribute 'startswith'"} ``` Server log (`docker logs`): ``` ERROR | open_webui.main:process_chat:2013 - Error processing chat payload: 'NoneType' object has no attribute 'startswith' INFO | ... "POST /api/v1/chat/completions HTTP/1.1" 400 ``` ## Expected Behavior HTTP 200 with a streamed or complete chat response — same as what the web UI receives. ## Analysis The error is logged at line 2013 of `main.py`: ```python except Exception as e: error_detail = e.detail if isinstance(e, HTTPException) else str(e) log.error('Error processing chat payload: %s', error_detail) # line 2013 ``` `error_detail = str(e)` is `'NoneType' object has no attribute 'startswith'` — the **original exception** is a `str.startswith()` call on `None` somewhere in the `try` block of `process_chat`. The crash likely originates in the routing/forwarding stack (model dispatch, pipeline resolution, or direct-connection handling) when a model field or URL is `None` — a code path only reached when `chat_id`, `parent_id`, and `session_id` are absent (i.e. external API clients). ## Additional Notes - `/api/v1/models` works correctly and returns the model list - The bug affects **all models**, including cloud-routed ones — not just locally-served models - No custom filters or pipes are active - Multiple external clients reproduce the issue; the web UI does **not** reproduce it - The full Python traceback is not logged — only `str(e)` is captured, which makes root-cause analysis harder ## Suggested Improvement Logging the full traceback in the exception handler would make root-cause analysis much easier: ```python except Exception as e: log.exception('Error processing chat payload') # logs full traceback error_detail = e.detail if isinstance(e, HTTPException) else str(e) ```
Author
Owner

@owui-terminator[bot] commented on GitHub (May 10, 2026):

⚠️ Missing Issue Title Prefix

@ThefloorMiner, your issue title is missing a categorising prefix (e.g. bug:, feat:, docs:).

Please update the title to lead with one of:

  • bug: bug report or error
  • feat: feature request or enhancement
  • docs: documentation issue
  • question: usage question
  • help: support request

Example: bug: Login fails when the password contains special characters

<!-- gh-comment-id:4416342911 --> @owui-terminator[bot] commented on GitHub (May 10, 2026): # ⚠️ Missing Issue Title Prefix @ThefloorMiner, your issue title is missing a categorising prefix (e.g. `bug:`, `feat:`, `docs:`). Please update the title to lead with one of: - **bug**: bug report or error - **feat**: feature request or enhancement - **docs**: documentation issue - **question**: usage question - **help**: support request Example: `bug: Login fails when the password contains special characters`
Author
Owner

@Classic298 commented on GitHub (May 10, 2026):

Cannot reproduce

<!-- gh-comment-id:4416378399 --> @Classic298 commented on GitHub (May 10, 2026): Cannot reproduce
Author
Owner

@Classic298 commented on GitHub (May 10, 2026):

latest

Image
<!-- gh-comment-id:4416380330 --> @Classic298 commented on GitHub (May 10, 2026): latest <img width="1157" height="438" alt="Image" src="https://github.com/user-attachments/assets/f1e89ad7-4dfc-46a6-96a9-8f705a17588d" />
Author
Owner

@xcjs commented on GitHub (May 10, 2026):

I've reproduced this in my environment as well - it's not the web frontend in which this is broken.

<!-- gh-comment-id:4416451694 --> @xcjs commented on GitHub (May 10, 2026): I've reproduced this in my environment as well - it's not the web frontend in which this is broken.
Author
Owner

@cslev commented on GitHub (May 11, 2026):

I have the same problem. Open Web UI works well in the browser, but sending a cURL request to be processed it requires a random "chat_id" in the POST content, because this is how it identifies with chat window to respond to. But via cURL or actually integrating it into copilot or any app, there is no such thing as "chat_id". I could resolve the issue in cURL as I can add that random chat_id, but OAI compatible copilot providers or the python API does not have this.

So, this works:

curl -s https://myollama.domain.com/api/chat/completions   -H "Authorization: Bearer sk-XXXXXXXX"   -H "Content-Type: application/json"   -d '{
    "model": "nemotron3:33b",
    "messages": [{"role": "user", "content": "Say hi in five words"}],
    "chat_id": "copilot-setup-test"
  }'| jq .

Without the chat_id, it does not. I was thinking that there might be an API-endpoint via /v1/ somewhere, but didn't find any. I found though that accessing models have two URLs (which looked promising in the beginning):

So this was working:

 curl https://myollama.domain.com/api/models  -H "Authorization: Bearer sk-XXXXXXXXXX"

just as well as:

 curl https://myollama.domain.com/api/v1/models  -H "Authorization: Bearer sk-XXXXXXXXXX"

But for api/chat/completitions there is no similar api/v1/chat/completions .... I mean there is, it works, but only with the "chat_id" also set.

<!-- gh-comment-id:4420721374 --> @cslev commented on GitHub (May 11, 2026): I have the same problem. Open Web UI works well in the browser, but sending a cURL request to be processed it requires a random "chat_id" in the POST content, because this is how it identifies with chat window to respond to. But via cURL or actually integrating it into copilot or any app, there is no such thing as "chat_id". I could resolve the issue in cURL as I can add that random chat_id, but OAI compatible copilot providers or the python API does not have this. So, this works: ``` curl -s https://myollama.domain.com/api/chat/completions -H "Authorization: Bearer sk-XXXXXXXX" -H "Content-Type: application/json" -d '{ "model": "nemotron3:33b", "messages": [{"role": "user", "content": "Say hi in five words"}], "chat_id": "copilot-setup-test" }'| jq . ``` Without the `chat_id`, it does not. I was thinking that there might be an API-endpoint via `/v1/` somewhere, but didn't find any. I found though that accessing models have two URLs (which looked promising in the beginning): So this was working: ``` curl https://myollama.domain.com/api/models -H "Authorization: Bearer sk-XXXXXXXXXX" ``` just as well as: ``` curl https://myollama.domain.com/api/v1/models -H "Authorization: Bearer sk-XXXXXXXXXX" ``` But for `api/chat/completitions` there is no similar `api/v1/chat/completions` .... I mean there is, it works, but only with the "chat_id" also set.
Author
Owner

@Classic298 commented on GitHub (May 11, 2026):

see https://github.com/open-webui/open-webui/issues/24553

<!-- gh-comment-id:4420736890 --> @Classic298 commented on GitHub (May 11, 2026): see https://github.com/open-webui/open-webui/issues/24553
Author
Owner

@sastrax commented on GitHub (May 12, 2026):

Reproducer from a different angle (UI path, OWUI 0.9.5, LiteLLM backend, SQLite)

I can reproduce a closely related variant of this bug in OWUI 0.9.5 from the web UI, not just from external API clients. Posting in case it helps re-open the investigation.

Setup:

  • OWUI ghcr.io/open-webui/open-webui:v0.9.5, fresh deploy (no migrated 0.8.12 DB)
  • SQLite backend (not Postgres)
  • LiteLLM proxy as the only configured OpenAI-compatible endpoint
  • direct.enable: false, auth.enable_api_keys: false — no direct connections
  • Model: gpt-5 (OpenAI o-series, reasoning model), routed via LiteLLM

Reproducer:

  1. Open a new chat in the web UI
  2. Select gpt-5 (or any o-series reasoning model)
  3. Send any prompt that triggers reasoning (e.g. "Is 9.11 or 9.9 greater? Think step by step.")
  4. The assistant message slot in the chat shows only the loading dot, never renders the response. The reply appears as a browser notification instead (with the actual answer).
  5. In the same chat, switch model to claude-sonnet-4-6 (or any non-reasoning model) and send another prompt
  6. Get a UI error toast: 'NoneType' object has no attribute 'startswith' — HTTP 400 from /api/chat/completions

Server log:

ERROR | open_webui.main:process_chat:2013 - Error processing chat payload: 'NoneType' object has no attribute 'startswith'
INFO  | ... "POST /api/chat/completions HTTP/1.1" 400

LiteLLM log shows the reasoning request was successful (200 OK) — so the upstream backend behaves correctly. The issue appears to be that the failed UI render in step 4 persists the assistant message with a None-valued field (probably chat_id or message_id on the persisted message), and the follow-up call (step 6) then trips over it inside process_chat.

Once the chat is in this state, every subsequent send in the same chat hits the same crash regardless of model. New chats are fine until the next reasoning request.

Workaround: delete the corrupted chat and avoid reasoning models on this version. Looks like two coupled bugs: the reasoning-stream UI render path, and the chat_id-None handling in process_chat:2013.

Happy to provide more logs or screenshots if useful.
Kind regards
Fabian

<!-- gh-comment-id:4431722329 --> @sastrax commented on GitHub (May 12, 2026): ### Reproducer from a different angle (UI path, OWUI 0.9.5, LiteLLM backend, SQLite) I can reproduce a closely related variant of this bug in OWUI 0.9.5 **from the web UI**, not just from external API clients. Posting in case it helps re-open the investigation. **Setup:** - OWUI `ghcr.io/open-webui/open-webui:v0.9.5`, fresh deploy (no migrated 0.8.12 DB) - SQLite backend (not Postgres) - LiteLLM proxy as the only configured OpenAI-compatible endpoint - `direct.enable: false`, `auth.enable_api_keys: false` — no direct connections - Model: `gpt-5` (OpenAI o-series, reasoning model), routed via LiteLLM **Reproducer:** 1. Open a new chat in the web UI 2. Select `gpt-5` (or any o-series reasoning model) 3. Send any prompt that triggers reasoning (e.g. `"Is 9.11 or 9.9 greater? Think step by step."`) 4. The assistant message slot in the chat shows only the loading dot, **never renders the response**. The reply appears as a browser notification instead (with the actual answer). 5. In the **same chat**, switch model to `claude-sonnet-4-6` (or any non-reasoning model) and send another prompt 6. Get a UI error toast: `'NoneType' object has no attribute 'startswith'` — HTTP 400 from `/api/chat/completions` **Server log:** ``` ERROR | open_webui.main:process_chat:2013 - Error processing chat payload: 'NoneType' object has no attribute 'startswith' INFO | ... "POST /api/chat/completions HTTP/1.1" 400 ``` **LiteLLM log shows the reasoning request was successful (200 OK)** — so the upstream backend behaves correctly. The issue appears to be that the failed UI render in step 4 persists the assistant message with a `None`-valued field (probably `chat_id` or `message_id` on the persisted message), and the follow-up call (step 6) then trips over it inside `process_chat`. Once the chat is in this state, every subsequent send in the same chat hits the same crash regardless of model. New chats are fine until the next reasoning request. **Workaround:** delete the corrupted chat and avoid reasoning models on this version. Looks like two coupled bugs: the reasoning-stream UI render path, and the chat_id-None handling in `process_chat:2013`. Happy to provide more logs or screenshots if useful. Kind regards Fabian
Author
Owner

@kevinchappell commented on GitHub (May 12, 2026):

I reproduced this by connecting to open webui api from opencode. #24556 fixed it for me

<!-- gh-comment-id:4434847710 --> @kevinchappell commented on GitHub (May 12, 2026): I reproduced this by connecting to open webui api from opencode. #24556 fixed it for me
Author
Owner

@thexavier666 commented on GitHub (May 15, 2026):

@cslev I was having the same issue as mentioned in this thread. I am using Python and I just modified my request to include chat_id. This fixed my issue. Thanks.

<!-- gh-comment-id:4458456018 --> @thexavier666 commented on GitHub (May 15, 2026): @cslev I was having the same issue as mentioned in this thread. I am using Python and I just modified my request to include `chat_id`. This fixed my issue. Thanks.
Author
Owner

@cslev commented on GitHub (May 16, 2026):

i can modify my requests too. But i want to use tools (langchain, or copilot), which does not have these. So I am waiting for the next release, especially a containerized version that does not have this issue anymore

<!-- gh-comment-id:4465142083 --> @cslev commented on GitHub (May 16, 2026): i can modify my requests too. But i want to use tools (langchain, or copilot), which does not have these. So I am waiting for the next release, especially a containerized version that does not have this issue anymore
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#123639