I have searched the existing issues and discussions.
I am using the latest version of Open WebUI.
Installation Method
Docker
Open WebUI Version
v0.6.26
Ollama Version (if applicable)
No response
Operating System
Garuda Linux
Browser (if applicable)
No response
Confirmation
I have read and followed all instructions in README.md.
I am using the latest version of both Open WebUI and Ollama.
I have included the browser console logs.
I have included the Docker container logs.
I have provided every relevant configuration, setting, and environment variable used in my setup.
I have clearly listed every relevant configuration, custom setting, environment variable, and command-line option that influences my setup (such as Docker Compose overrides, .env values, browser settings, authentication configurations, etc).
I have documented step-by-step reproduction instructions that are precise, sequential, and leave nothing to interpretation. My steps:
Start with the initial platform/version/OS and dependencies used,
Specify exact install/launch/configure commands,
List URLs visited, user input (incl. example values/emails/passwords if needed),
Describe all options and toggles enabled or changed,
Include any files or environmental changes,
Identify the expected and actual result at each stage,
Ensure any reasonably skilled user can follow and hit the same issue.
Expected Behavior
It should only send a system instruction to the provider.
Actual Behavior
Duplicate system instructions are being sent
Steps to Reproduce
I tried both with Docker and by installing via uvx using the command DATA_DIR=~/.open-webui uvx --python 3.11 open-webui@latest serve --port 8082
Install a clean version of OpenWebUI.
Configure a provider of your choice (I use LiteLLM Proxy).
Set a system instruction; I used "You talk as a pirate."
Check the request logs sent to the provider and you will notice that "You talk as a pirate\nYou talk as a pirate" is being sent.
Logs & Screenshots
This is the message sent by OWUI
The request sent from the browser to the backend
{"stream":true,"model":"GPT-OSS-20B-Cline","messages":[{"role":"system","content":"You talk as a pirate"},{"role":"user","content":"hi"}],"params":{"system":"You talk as a pirate"},"tool_servers":[],"features":{"image_generation":false,"code_interpreter":false,"web_search":false,"memory":false},"variables":{"{{USER_NAME}}":"User","{{USER_LOCATION}}":"Unknown","{{CURRENT_DATETIME}}":"2025-09-04 11:54:56","{{CURRENT_DATE}}":"2025-09-04","{{CURRENT_TIME}}":"11:54:56","{{CURRENT_WEEKDAY}}":"Thursday","{{CURRENT_TIMEZONE}}":"Europe/Rome","{{USER_LANGUAGE}}":"it-IT"},"model_item":{"id":"GPT-OSS-20B-Cline","object":"model","created":1677610602,"owned_by":"openai","connection_type":"external","name":"GPT-OSS-20B-Cline","openai":{"id":"GPT-OSS-20B-Cline","object":"model","created":1677610602,"owned_by":"openai","connection_type":"external"},"urlIdx":0,"actions":[],"filters":[],"tags":[]},"session_id":"a91VsVEKryJM73ioAAAB","chat_id":"386e91ea-56a8-4a34-967f-d3e2b0941e51","id":"3139f820-ee16-4931-856e-562ac703c599","background_tasks":{"title_generation":true,"tags_generation":true,"follow_up_generation":true}}
The request received from the LiteLLM proxy
Additional Information
I narrowed the problem area and determined that it is an OWUI bug. I confirmed this by using a different client to submit requests; the requests were logged correctly.
My Docker installation was running version v0.6.25. After detecting the bug, I upgraded to v0.6.26, yet the issue remained.
To rule out environment‑specific factors, I set up a fresh machine with no prior OWUI installation and executed the following command: DATA_DIR=~/.open-webui uvx --python 3.11 open-webui@latest serve --port 8082
Originally created by @DanielusG on GitHub (Sep 4, 2025).
Original GitHub issue: https://github.com/open-webui/open-webui/issues/17198
### Check Existing Issues
- [x] I have searched the existing issues and discussions.
- [x] I am using the latest version of Open WebUI.
### Installation Method
Docker
### Open WebUI Version
v0.6.26
### Ollama Version (if applicable)
_No response_
### Operating System
Garuda Linux
### Browser (if applicable)
_No response_
### Confirmation
- [x] I have read and followed all instructions in `README.md`.
- [x] I am using the latest version of **both** Open WebUI and Ollama.
- [x] I have included the browser console logs.
- [x] I have included the Docker container logs.
- [x] I have **provided every relevant configuration, setting, and environment variable used in my setup.**
- [x] I have clearly **listed every relevant configuration, custom setting, environment variable, and command-line option that influences my setup** (such as Docker Compose overrides, .env values, browser settings, authentication configurations, etc).
- [x] I have documented **step-by-step reproduction instructions that are precise, sequential, and leave nothing to interpretation**. My steps:
- Start with the initial platform/version/OS and dependencies used,
- Specify exact install/launch/configure commands,
- List URLs visited, user input (incl. example values/emails/passwords if needed),
- Describe all options and toggles enabled or changed,
- Include any files or environmental changes,
- Identify the expected and actual result at each stage,
- Ensure any reasonably skilled user can follow and hit the same issue.
### Expected Behavior
It should only send a system instruction to the provider.
### Actual Behavior
Duplicate system instructions are being sent
### Steps to Reproduce
I tried both with Docker and by installing via `uvx` using the command `DATA_DIR=~/.open-webui uvx --python 3.11 open-webui@latest serve --port 8082`
1. Install a clean version of OpenWebUI.
2. Configure a provider of your choice (I use LiteLLM Proxy).
3. Set a system instruction; I used "You talk as a pirate."
4. Check the request logs sent to the provider and you will notice that "You talk as a pirate\nYou talk as a pirate" is being sent.
### Logs & Screenshots
<img width="1081" height="295" alt="Image" src="https://github.com/user-attachments/assets/52d5e29b-9acb-4384-8886-c034c0736bed" />
This is the message sent by OWUI
---
<img width="855" height="306" alt="Image" src="https://github.com/user-attachments/assets/ec418ac6-caf9-4629-b20a-2a83e7dc3684" />
The request sent from the browser to the backend
`{"stream":true,"model":"GPT-OSS-20B-Cline","messages":[{"role":"system","content":"You talk as a pirate"},{"role":"user","content":"hi"}],"params":{"system":"You talk as a pirate"},"tool_servers":[],"features":{"image_generation":false,"code_interpreter":false,"web_search":false,"memory":false},"variables":{"{{USER_NAME}}":"User","{{USER_LOCATION}}":"Unknown","{{CURRENT_DATETIME}}":"2025-09-04 11:54:56","{{CURRENT_DATE}}":"2025-09-04","{{CURRENT_TIME}}":"11:54:56","{{CURRENT_WEEKDAY}}":"Thursday","{{CURRENT_TIMEZONE}}":"Europe/Rome","{{USER_LANGUAGE}}":"it-IT"},"model_item":{"id":"GPT-OSS-20B-Cline","object":"model","created":1677610602,"owned_by":"openai","connection_type":"external","name":"GPT-OSS-20B-Cline","openai":{"id":"GPT-OSS-20B-Cline","object":"model","created":1677610602,"owned_by":"openai","connection_type":"external"},"urlIdx":0,"actions":[],"filters":[],"tags":[]},"session_id":"a91VsVEKryJM73ioAAAB","chat_id":"386e91ea-56a8-4a34-967f-d3e2b0941e51","id":"3139f820-ee16-4931-856e-562ac703c599","background_tasks":{"title_generation":true,"tags_generation":true,"follow_up_generation":true}}`
---
<img width="716" height="671" alt="Image" src="https://github.com/user-attachments/assets/66829d52-3ce3-4185-a257-bb8ed0f7581d" />
The request received from the LiteLLM proxy
### Additional Information
I narrowed the problem area and determined that it is an OWUI bug. I confirmed this by using a different client to submit requests; the requests were logged correctly.
My Docker installation was running version v0.6.25. After detecting the bug, I upgraded to v0.6.26, yet the issue remained.
To rule out environment‑specific factors, I set up a fresh machine with no prior OWUI installation and executed the following command:
`DATA_DIR=~/.open-webui uvx --python 3.11 open-webui@latest serve --port 8082`
GiteaMirror
added the bug label 2026-05-25 08:50:46 -05:00
I can see all the log but seem that it have configurated title & tag generation, if it's the case there are one request for each generation (tittle & tags)
<!-- gh-comment-id:3253360422 -->
@rgaricano commented on GitHub (Sep 4, 2025):
I can see all the log but seem that it have configurated title & tag generation, if it's the case there are one request for each generation (tittle & tags)
I can see all the log but seem that it have configurated title & tag generation, if it's the case there are one request for each generation (tittle & tags)
I'm not referring to multiple requests, but rather a single request containing the 'system' field with the system instruction value duplicated – specifically, it appears twice, separated by a newline character (\n), as can be seen in the screenshot.
For the sake of completeness, I will also specify that in the Docker installation, I have disabled the generation of tag titles, etc. The request sent is a single one, and it contains that error.
<!-- gh-comment-id:3254113164 -->
@DanielusG commented on GitHub (Sep 4, 2025):
> I can see all the log but seem that it have configurated title & tag generation, if it's the case there are one request for each generation (tittle & tags)
I'm not referring to multiple requests, but rather a single request containing the 'system' field with the system instruction value duplicated – specifically, it appears twice, separated by a newline character (\n), as can be seen in the screenshot.
For the sake of completeness, I will also specify that in the Docker installation, I have disabled the generation of tag titles, etc. The request sent is a single one, and it contains that error.
If you ask about roles system & user messages,
It isn't a bug, It's how, right now, it work: the whole conversation is sended, and those are 2 messages. It's the providers protocol.
Yes, it's a waste of resources and not very logical, which is why history and cache systems are being implemented in this kind of systems and services.
I also hope that in Open-WebUI, at least for locally served models, we can achieve these types of improvements, but with respect to external providers, it will always depend on their protocols.
(maybe I'm offuscated but I can't see any duplicated system and new line in the screenshots provided)
<!-- gh-comment-id:3255166543 -->
@rgaricano commented on GitHub (Sep 4, 2025):
Sorry Danielle, but I don't see it.
i only see a json with this info (a normal request):
```
root
├── stream (boolean)
│ └── true
├── model
│ └── GPT-OSS-20B-Cline
├── session_id
│ └── a91VsVEKryJM73ioAAAB
├── chat_id
│ └── 386e91ea-56a8-4a34-967f-d3e2b0941e51
├── id
│ └── 3139f820-ee16-4931-856e-562ac703c599
├── system
│ └── messages
│ ├── role (string)
│ │ └── system
│ └── content (string)
│ └── You talk as a pirate
├── user
│ └── messages
│ ├── role (string)
│ │ └── user
│ └── content (string)
│ └── hi
├── params
│ └── system (string)
│ └── You talk as a pirate
├── tool_servers
│ └── [] (empty array)
├── features
│ ├── image_generation (boolean)
│ │ └── false
│ ├── code_interpreter (boolean)
│ │ └── false
│ ├── web_search (boolean)
│ │ └── false
│ ├── memory (boolean)
│ │ └── false
├── variables
│ ├── USER_NAME (string)
│ │ └── User
│ ├── USER_LOCATION (string)
│ │ └── Unknown
│ ├── CURRENT_DATETIME (datetime)
│ │ └── 2025-09-04 11:54:56
│ ├── CURRENT_DATE (date)
│ │ └── 2025-09-04
│ ├── CURRENT_TIME (time)
│ │ └── 11:54:56
│ ├── CURRENT_WEEKDAY (string)
│ │ └── Thursday
│ ├── CURRENT_TIMEZONE (string)
│ │ └── Europe/Rome
│ ├── USER_LANGUAGE (string)
│ │ └── it-IT
├── model_item
│ ├── id (string)
│ │ └── GPT-OSS-20B-Cline
│ ├── object (string)
│ │ └── model
│ ├── created (integer)
│ │ └── 1677610602
│ ├── owned_by (string)
│ │ └── openai
│ ├── connection_type (string)
│ │ └── external
│ ├── name (string)
│ │ └── GPT-OSS-20B-Cline
│ ├── openai
│ │ ├── id (string)
│ │ │ └── GPT-OSS-20B-Cline
│ │ ├── object (string)
│ │ │ └── model
│ │ ├── created (integer)
│ │ │ └── 1677610602
│ │ ├── owned_by (string)
│ │ │ └── openai
│ │ ├── connection_type (string)
│ │ │ └── external
│ ├── urlIdx (integer)
│ │ └── 0
│ ├── actions (array)
│ │ └── []
│ ├── filters (array)
│ │ └── []
│ ├── tags (array)
│ │ └── []
└── background_tasks
├── title_generation (boolean)
│ └── true
├── tags_generation (boolean)
│ └── true
└── follow_up_generation (boolean)
└── true
```
If you ask about roles system & user messages,
It isn't a bug, It's how, right now, it work: the whole conversation is sended, and those are 2 messages. It's the providers protocol.
Yes, it's a waste of resources and not very logical, which is why history and cache systems are being implemented in this kind of systems and services.
I also hope that in Open-WebUI, at least for locally served models, we can achieve these types of improvements, but with respect to external providers, it will always depend on their protocols.
(maybe I'm offuscated but I can't see any duplicated system and new line in the screenshots provided)
@rgaricano I'm still not sure you understood the report. It says the system prompt string gets duplicated inside the system message content. Nothing else.
<!-- gh-comment-id:3257087150 -->
@Ithanil commented on GitHub (Sep 5, 2025):
I also don't reproduce, but because this has been reported before (https://github.com/open-webui/open-webui/issues/16855) I assume there is an actual issue to be reproduced somehow.
@rgaricano I'm still not sure you understood the report. It says the system prompt string gets duplicated inside the system message content. Nothing else.
I also don't reproduce, but because this has been reported before (#16855) I assume there is an actual issue to be reproduced somehow.
@rgaricano I'm still not sure you understood the report. It says the system prompt string gets duplicated inside the system message content. Nothing else.
I believe the confusion arises from the fact that I added a log that is correctly structured.
In my report you can see that I added three screenshots.
The first image shows what the end user clearly sees and what they expect the provider to receive as a request.
The second screenshot captures the browser’s HTTP request (OpenWebUI frontend → OpenWebUI backend) and shows that the request is correctly formulated and contains no duplicates.
The error occurs during the transition from the OpenWebUI backend to the provider (in this case LiteLLM). As shown in the last screenshot, the system message received by LiteLLM is “You talk as a pirate\nYou talk as a pirate” even though my prompt was simply “You talk as a pirate”.
To reproduce the bug I created a very simple backend that emulates an LLM provider and logs the system prompt received in the terminal. Steps to reproduce the issue:
Install fastapi and uvicorn in a Python environment.
Run the simulated middleware (code below).
Add a new provider to OWUI with the middleware’s IP.
Start a new chat called “dumb-model”.
Set any system prompt.
Notice that the middleware’s terminal will show the duplicated system prompt.
Middleware code:
fromfastapiimportFastAPIfrompydanticimportBaseModelfromtypingimportList,Optional,Dict,Anyimporttimeimportlogging# Set up logging to show in terminallogging.basicConfig(level=logging.INFO,format='%(asctime)s - %(message)s')logger=logging.getLogger(__name__)app=FastAPI(title="Dumb Middleware",version="1.0.0")# Models for the chat completions endpointclassMessage(BaseModel):role:strcontent:strclassChatCompletionRequest(BaseModel):model:strmessages:List[Message]temperature:Optional[float]=1.0max_tokens:Optional[int]=Nonestream:Optional[bool]=FalseclassChatCompletionChoice(BaseModel):index:intmessage:Messagefinish_reason:strclassChatCompletionUsage(BaseModel):prompt_tokens:intcompletion_tokens:inttotal_tokens:intclassChatCompletionResponse(BaseModel):id:strobject:str="chat.completion"created:intmodel:strchoices:List[ChatCompletionChoice]usage:ChatCompletionUsageclassModel(BaseModel):id:strobject:str="model"created:intowned_by:str="dumb-middleware"permission:List[Dict[str,Any]]=[]root:Optional[str]=Noneparent:Optional[str]=Nonedef__init__(self,**data):super().__init__(**data)ifself.rootisNone:self.root=self.idclassModelsResponse(BaseModel):object:str="list"data:List[Model]@app.get("/v1/models",response_model=ModelsResponse)asyncdefget_models():"""Return the available models in OpenAI compatible format"""returnModelsResponse(object="list",data=[Model(id="dumb-model",object="model",created=int(time.time()),owned_by="dumb-middleware",permission=[],root="dumb-model",parent=None)])@app.post("/v1/chat/completions",response_model=ChatCompletionResponse)asyncdefchat_completions(request:ChatCompletionRequest):"""Handle chat completions and log system messages"""# Find and log system messagesystem_messages=[msgformsginrequest.messagesifmsg.role=="system"]ifsystem_messages:forsystem_msginsystem_messages:logger.info(f"System message: {system_msg.content}")else:logger.info("No system message found in request")# # Log all messages for debugging# logger.info(f"Received {len(request.messages)} messages")# for i, msg in enumerate(request.messages):# logger.info(f"Message {i}: [{msg.role}] {msg.content}")# Create the responseresponse_message=Message(role="assistant",content="hi from dumb middleware")logger.info(f"Response: {response_message.content}")returnChatCompletionResponse(id=f"chatcmpl-{int(time.time())}",created=int(time.time()),model=request.model,choices=[ChatCompletionChoice(index=0,message=response_message,finish_reason="stop")],usage=ChatCompletionUsage(prompt_tokens=sum(len(msg.content.split())formsginrequest.messages),completion_tokens=len(response_message.content.split()),total_tokens=sum(len(msg.content.split())formsginrequest.messages)+len(response_message.content.split())))if__name__=="__main__":importuvicornuvicorn.run(app,host="0.0.0.0",port=8181)
<!-- gh-comment-id:3257298912 -->
@DanielusG commented on GitHub (Sep 5, 2025):
> I also don't reproduce, but because this has been reported before ([#16855](https://github.com/open-webui/open-webui/issues/16855)) I assume there is an actual issue to be reproduced somehow.
>
> [@rgaricano](https://github.com/rgaricano) I'm still not sure you understood the report. It says the system prompt string gets duplicated inside the system message content. Nothing else.
I believe the confusion arises from the fact that I added a log that is correctly structured.
In my report you can see that I added three screenshots.
The first image shows what the end user clearly sees and what they expect the provider to receive as a request.
The second screenshot captures the browser’s HTTP request (OpenWebUI frontend → OpenWebUI backend) and shows that the request is correctly formulated and contains no duplicates.
The error occurs during the transition from the OpenWebUI backend to the provider (in this case LiteLLM). As shown in the last screenshot, the system message received by LiteLLM is “You talk as a pirate\nYou talk as a pirate” even though my prompt was simply “You talk as a pirate”.
To reproduce the bug I created a very simple backend that emulates an LLM provider and logs the system prompt received in the terminal.
**Steps to reproduce the issue:**
1. Install `fastapi` and `uvicorn` in a Python environment.
2. Run the simulated middleware (code below).
3. Add a new provider to OWUI with the middleware’s IP.
4. Start a new chat called “dumb-model”.
5. Set any system prompt.
6. Notice that the middleware’s terminal will show the duplicated system prompt.
**Middleware code:**
```python
from fastapi import FastAPI
from pydantic import BaseModel
from typing import List, Optional, Dict, Any
import time
import logging
# Set up logging to show in terminal
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
logger = logging.getLogger(__name__)
app = FastAPI(title="Dumb Middleware", version="1.0.0")
# Models for the chat completions endpoint
class Message(BaseModel):
role: str
content: str
class ChatCompletionRequest(BaseModel):
model: str
messages: List[Message]
temperature: Optional[float] = 1.0
max_tokens: Optional[int] = None
stream: Optional[bool] = False
class ChatCompletionChoice(BaseModel):
index: int
message: Message
finish_reason: str
class ChatCompletionUsage(BaseModel):
prompt_tokens: int
completion_tokens: int
total_tokens: int
class ChatCompletionResponse(BaseModel):
id: str
object: str = "chat.completion"
created: int
model: str
choices: List[ChatCompletionChoice]
usage: ChatCompletionUsage
class Model(BaseModel):
id: str
object: str = "model"
created: int
owned_by: str = "dumb-middleware"
permission: List[Dict[str, Any]] = []
root: Optional[str] = None
parent: Optional[str] = None
def __init__(self, **data):
super().__init__(**data)
if self.root is None:
self.root = self.id
class ModelsResponse(BaseModel):
object: str = "list"
data: List[Model]
@app.get("/v1/models", response_model=ModelsResponse)
async def get_models():
"""Return the available models in OpenAI compatible format"""
return ModelsResponse(
object="list",
data=[
Model(
id="dumb-model",
object="model",
created=int(time.time()),
owned_by="dumb-middleware",
permission=[],
root="dumb-model",
parent=None
)
]
)
@app.post("/v1/chat/completions", response_model=ChatCompletionResponse)
async def chat_completions(request: ChatCompletionRequest):
"""Handle chat completions and log system messages"""
# Find and log system message
system_messages = [msg for msg in request.messages if msg.role == "system"]
if system_messages:
for system_msg in system_messages:
logger.info(f"System message: {system_msg.content}")
else:
logger.info("No system message found in request")
# # Log all messages for debugging
# logger.info(f"Received {len(request.messages)} messages")
# for i, msg in enumerate(request.messages):
# logger.info(f"Message {i}: [{msg.role}] {msg.content}")
# Create the response
response_message = Message(
role="assistant",
content="hi from dumb middleware"
)
logger.info(f"Response: {response_message.content}")
return ChatCompletionResponse(
id=f"chatcmpl-{int(time.time())}",
created=int(time.time()),
model=request.model,
choices=[
ChatCompletionChoice(
index=0,
message=response_message,
finish_reason="stop"
)
],
usage=ChatCompletionUsage(
prompt_tokens=sum(len(msg.content.split()) for msg in request.messages),
completion_tokens=len(response_message.content.split()),
total_tokens=sum(len(msg.content.split()) for msg in request.messages) + len(response_message.content.split())
)
)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8181)
```
Try to set the system prompt manually, it seems like the system prompt from the memory feature right? Try to define a pirate prompt like in my case
<!-- gh-comment-id:3257895037 -->
@DanielusG commented on GitHub (Sep 5, 2025):
> Request: model='dumb-model' messages=[Message(role='system', content='User Context:\n\n')
Try to set the system prompt manually, it seems like the system prompt from the memory feature right? Try to define a pirate prompt like in my case
025-09-05 12:45:51,010 - Request: model='dumb-model' messages=[Message(role='system', content='You talk as a pirate\nYou talk as a pirate\nUser Context:\n\n'), Message(role='user', content='test'), Message(role='assistant', content='response to system1 hi from dumb middleware'), Message(role='user', content='test1')] temperature=1.0 max_tokens=None stream=True
2025-09-05 12:45:51,010 - System_messages: [Message(role='system', content='You talk as a pirate\nYou talk as a pirate\nUser Context:\n\n')]
2025-09-05 12:45:51,010 - System message1 content: "You talk as a pirate
You talk as a pirate
User Context:
"
2025-09-05 12:45:51,010 - User message1 content: test
2025-09-05 12:45:51,010 - User message2 content: test1
2025-09-05 12:45:51,011 - Response: role='assistant' content='response to system1 hi from dumb middleware'
INFO: 127.0.0.1:54022 - "POST /v1/chat/completions HTTP/1.1" 200 OK
INFO: 127.0.0.1:54030 - "GET /v1/models HTTP/1.1" 200 OK
2025-09-05 12:45:55,915 - Request: model='dumb-model' messages=[Message(role='system', content='You talk as a pirate\nYou talk as a pirate\nUser Context:\n\n'), Message(role='user', content='test'), Message(role='assistant', content='response to system1 hi from dumb middleware'), Message(role='user', content='test1'), Message(role='assistant', content='response to system1 hi from dumb middleware'), Message(role='user', content='test2')] temperature=1.0 max_tokens=None stream=True
2025-09-05 12:45:55,915 - System_messages: [Message(role='system', content='You talk as a pirate\nYou talk as a pirate\nUser Context:\n\n')]
2025-09-05 12:45:55,915 - System message1 content: "You talk as a pirate
You talk as a pirate
User Context:
"
2025-09-05 12:45:55,915 - User message1 content: test
2025-09-05 12:45:55,915 - User message2 content: test1
2025-09-05 12:45:55,915 - User message3 content: test2
2025-09-05 12:45:55,915 - Response: role='assistant' content='response to system1 hi from dumb middleware'
INFO: 127.0.0.1:54042 - "POST /v1/chat/completions HTTP/1.1" 200 OK
<!-- gh-comment-id:3257928377 -->
@rgaricano commented on GitHub (Sep 5, 2025):
yes, i see
(tested with dev branch)
```
025-09-05 12:45:51,010 - Request: model='dumb-model' messages=[Message(role='system', content='You talk as a pirate\nYou talk as a pirate\nUser Context:\n\n'), Message(role='user', content='test'), Message(role='assistant', content='response to system1 hi from dumb middleware'), Message(role='user', content='test1')] temperature=1.0 max_tokens=None stream=True
2025-09-05 12:45:51,010 - System_messages: [Message(role='system', content='You talk as a pirate\nYou talk as a pirate\nUser Context:\n\n')]
2025-09-05 12:45:51,010 - System message1 content: "You talk as a pirate
You talk as a pirate
User Context:
"
2025-09-05 12:45:51,010 - User message1 content: test
2025-09-05 12:45:51,010 - User message2 content: test1
2025-09-05 12:45:51,011 - Response: role='assistant' content='response to system1 hi from dumb middleware'
INFO: 127.0.0.1:54022 - "POST /v1/chat/completions HTTP/1.1" 200 OK
INFO: 127.0.0.1:54030 - "GET /v1/models HTTP/1.1" 200 OK
2025-09-05 12:45:55,915 - Request: model='dumb-model' messages=[Message(role='system', content='You talk as a pirate\nYou talk as a pirate\nUser Context:\n\n'), Message(role='user', content='test'), Message(role='assistant', content='response to system1 hi from dumb middleware'), Message(role='user', content='test1'), Message(role='assistant', content='response to system1 hi from dumb middleware'), Message(role='user', content='test2')] temperature=1.0 max_tokens=None stream=True
2025-09-05 12:45:55,915 - System_messages: [Message(role='system', content='You talk as a pirate\nYou talk as a pirate\nUser Context:\n\n')]
2025-09-05 12:45:55,915 - System message1 content: "You talk as a pirate
You talk as a pirate
User Context:
"
2025-09-05 12:45:55,915 - User message1 content: test
2025-09-05 12:45:55,915 - User message2 content: test1
2025-09-05 12:45:55,915 - User message3 content: test2
2025-09-05 12:45:55,915 - Response: role='assistant' content='response to system1 hi from dumb middleware'
INFO: 127.0.0.1:54042 - "POST /v1/chat/completions HTTP/1.1" 200 OK
```
def add_or_update_system_message(
content: str, messages: list[dict], append: bool = False
):
"""
Adds a new system message at the beginning of the messages list
or updates the existing system message at the beginning.
:param msg: The message to be added or appended.
:param messages: The list of message dictionaries.
:return: The updated list of message dictionaries.
"""
if messages and messages[0].get("role") == "system":
existing_content = messages[0]["content"]
existing_lines = set(existing_content.split('\n'))
new_lines = content.split('\n')
unique_new_lines = [line for line in new_lines if line not in existing_lines]
if unique_new_lines:
unique_content = '\n'.join(unique_new_lines)
if append:
messages[0]["content"] = f"{existing_content}\n{unique_content}"
else:
messages[0]["content"] = f"{unique_content}\n{existing_content}"
else:
messages.insert(0, {"role": "system", "content": content})
return messages
now working with the fix:
NFO: Uvicorn running on http://0.0.0.0:8181 (Press CTRL+C to quit)
INFO: 127.0.0.1:40602 - "GET /v1/models HTTP/1.1" 200 OK
2025-09-05 13:03:18,639 - Request: model='dumb-model' messages=[Message(role='system', content='You talk as a pirate\nUser Context:\n\n'), Message(role='user', content='test')] temperature=1.0 max_tokens=None stream=True
2025-09-05 13:03:18,639 - System_messages: [Message(role='system', content='You talk as a pirate\nUser Context:\n\n')]
2025-09-05 13:03:18,639 - System message1 content: "You talk as a pirate
User Context:
"
2025-09-05 13:03:18,639 - User message1 content: test
2025-09-05 13:03:18,639 - Response: role='assistant' content='response to system1 hi from dumb middleware'
INFO: 127.0.0.1:40606 - "POST /v1/chat/completions HTTP/1.1" 200 OK
INFO: 127.0.0.1:40620 - "GET /v1/models HTTP/1.1" 200 OK
2025-09-05 13:03:23,170 - Request: model='dumb-model' messages=[Message(role='system', content='You talk as a pirate\nUser Context:\n\n'), Message(role='user', content='test'), Message(role='assistant', content='response to system1 hi from dumb middleware'), Message(role='user', content='test1')] temperature=1.0 max_tokens=None stream=True
2025-09-05 13:03:23,170 - System_messages: [Message(role='system', content='You talk as a pirate\nUser Context:\n\n')]
2025-09-05 13:03:23,170 - System message1 content: "You talk as a pirate
User Context:
"
2025-09-05 13:03:23,170 - User message1 content: test
2025-09-05 13:03:23,170 - User message2 content: test1
2025-09-05 13:03:23,170 - Response: role='assistant' content='response to system1 hi from dumb middleware'
INFO: 127.0.0.1:40628 - "POST /v1/chat/completions HTTP/1.1" 200 OK
INFO: 127.0.0.1:34122 - "GET /v1/models HTTP/1.1" 200 OK
2025-09-05 13:03:29,893 - Request: model='dumb-model' messages=[Message(role='system', content='You talk as a pirate\nUser Context:\n\n'), Message(role='user', content='test'), Message(role='assistant', content='response to system1 hi from dumb middleware'), Message(role='user', content='test1'), Message(role='assistant', content='response to system1 hi from dumb middleware'), Message(role='user', content='test2')] temperature=1.0 max_tokens=None stream=True
2025-09-05 13:03:29,893 - System_messages: [Message(role='system', content='You talk as a pirate\nUser Context:\n\n')]
2025-09-05 13:03:29,893 - System message1 content: "You talk as a pirate
User Context:
"
2025-09-05 13:03:29,893 - User message1 content: test
2025-09-05 13:03:29,893 - User message2 content: test1
2025-09-05 13:03:29,893 - User message3 content: test2
2025-09-05 13:03:29,893 - Response: role='assistant' content='response to system1 hi from dumb middleware'
INFO: 127.0.0.1:34134 - "POST /v1/chat/completions HTTP/1.1" 200 OK
NOTE:
I didn't made a PR, sure that @tjbck find a better way.
<!-- gh-comment-id:3258023960 -->
@rgaricano commented on GitHub (Sep 5, 2025):
The duplication occurs because apply_system_prompt_to_body calls add_or_update_system_message multiple times during request processing.
The fix (as is a small function I put the whole function)
Replace function:
https://github.com/open-webui/open-webui/blob/2407d9b905978d68619bdce4021e424046ec8df9/backend/open_webui/utils/misc.py#L138
by:
```
def add_or_update_system_message(
content: str, messages: list[dict], append: bool = False
):
"""
Adds a new system message at the beginning of the messages list
or updates the existing system message at the beginning.
:param msg: The message to be added or appended.
:param messages: The list of message dictionaries.
:return: The updated list of message dictionaries.
"""
if messages and messages[0].get("role") == "system":
existing_content = messages[0]["content"]
existing_lines = set(existing_content.split('\n'))
new_lines = content.split('\n')
unique_new_lines = [line for line in new_lines if line not in existing_lines]
if unique_new_lines:
unique_content = '\n'.join(unique_new_lines)
if append:
messages[0]["content"] = f"{existing_content}\n{unique_content}"
else:
messages[0]["content"] = f"{unique_content}\n{existing_content}"
else:
messages.insert(0, {"role": "system", "content": content})
return messages
```
now working with the fix:
```
NFO: Uvicorn running on http://0.0.0.0:8181 (Press CTRL+C to quit)
INFO: 127.0.0.1:40602 - "GET /v1/models HTTP/1.1" 200 OK
2025-09-05 13:03:18,639 - Request: model='dumb-model' messages=[Message(role='system', content='You talk as a pirate\nUser Context:\n\n'), Message(role='user', content='test')] temperature=1.0 max_tokens=None stream=True
2025-09-05 13:03:18,639 - System_messages: [Message(role='system', content='You talk as a pirate\nUser Context:\n\n')]
2025-09-05 13:03:18,639 - System message1 content: "You talk as a pirate
User Context:
"
2025-09-05 13:03:18,639 - User message1 content: test
2025-09-05 13:03:18,639 - Response: role='assistant' content='response to system1 hi from dumb middleware'
INFO: 127.0.0.1:40606 - "POST /v1/chat/completions HTTP/1.1" 200 OK
INFO: 127.0.0.1:40620 - "GET /v1/models HTTP/1.1" 200 OK
2025-09-05 13:03:23,170 - Request: model='dumb-model' messages=[Message(role='system', content='You talk as a pirate\nUser Context:\n\n'), Message(role='user', content='test'), Message(role='assistant', content='response to system1 hi from dumb middleware'), Message(role='user', content='test1')] temperature=1.0 max_tokens=None stream=True
2025-09-05 13:03:23,170 - System_messages: [Message(role='system', content='You talk as a pirate\nUser Context:\n\n')]
2025-09-05 13:03:23,170 - System message1 content: "You talk as a pirate
User Context:
"
2025-09-05 13:03:23,170 - User message1 content: test
2025-09-05 13:03:23,170 - User message2 content: test1
2025-09-05 13:03:23,170 - Response: role='assistant' content='response to system1 hi from dumb middleware'
INFO: 127.0.0.1:40628 - "POST /v1/chat/completions HTTP/1.1" 200 OK
INFO: 127.0.0.1:34122 - "GET /v1/models HTTP/1.1" 200 OK
2025-09-05 13:03:29,893 - Request: model='dumb-model' messages=[Message(role='system', content='You talk as a pirate\nUser Context:\n\n'), Message(role='user', content='test'), Message(role='assistant', content='response to system1 hi from dumb middleware'), Message(role='user', content='test1'), Message(role='assistant', content='response to system1 hi from dumb middleware'), Message(role='user', content='test2')] temperature=1.0 max_tokens=None stream=True
2025-09-05 13:03:29,893 - System_messages: [Message(role='system', content='You talk as a pirate\nUser Context:\n\n')]
2025-09-05 13:03:29,893 - System message1 content: "You talk as a pirate
User Context:
"
2025-09-05 13:03:29,893 - User message1 content: test
2025-09-05 13:03:29,893 - User message2 content: test1
2025-09-05 13:03:29,893 - User message3 content: test2
2025-09-05 13:03:29,893 - Response: role='assistant' content='response to system1 hi from dumb middleware'
INFO: 127.0.0.1:34134 - "POST /v1/chat/completions HTTP/1.1" 200 OK
```
----------
NOTE:
I didn't made a PR, sure that @tjbck find a better way.
Any news? For those who heavily use system prompts in OpenWebUI, this bug is extremely penalizing; the models do not respond well to duplicated system prompts. For example, if the prompt were 11k tokens, the provider and the model receive a full 22k of duplicate instructions. it's a critical bug!
<!-- gh-comment-id:3353045567 -->
@DanielusG commented on GitHub (Sep 30, 2025):
Any news? For those who heavily use system prompts in OpenWebUI, this bug is extremely penalizing; the models do not respond well to duplicated system prompts. For example, if the prompt were 11k tokens, the provider and the model receive a full 22k of duplicate instructions. it's a critical bug!
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Originally created by @DanielusG on GitHub (Sep 4, 2025).
Original GitHub issue: https://github.com/open-webui/open-webui/issues/17198
Check Existing Issues
Installation Method
Docker
Open WebUI Version
v0.6.26
Ollama Version (if applicable)
No response
Operating System
Garuda Linux
Browser (if applicable)
No response
Confirmation
README.md.Expected Behavior
It should only send a system instruction to the provider.
Actual Behavior
Duplicate system instructions are being sent
Steps to Reproduce
I tried both with Docker and by installing via
uvxusing the commandDATA_DIR=~/.open-webui uvx --python 3.11 open-webui@latest serve --port 8082Logs & Screenshots
{"stream":true,"model":"GPT-OSS-20B-Cline","messages":[{"role":"system","content":"You talk as a pirate"},{"role":"user","content":"hi"}],"params":{"system":"You talk as a pirate"},"tool_servers":[],"features":{"image_generation":false,"code_interpreter":false,"web_search":false,"memory":false},"variables":{"{{USER_NAME}}":"User","{{USER_LOCATION}}":"Unknown","{{CURRENT_DATETIME}}":"2025-09-04 11:54:56","{{CURRENT_DATE}}":"2025-09-04","{{CURRENT_TIME}}":"11:54:56","{{CURRENT_WEEKDAY}}":"Thursday","{{CURRENT_TIMEZONE}}":"Europe/Rome","{{USER_LANGUAGE}}":"it-IT"},"model_item":{"id":"GPT-OSS-20B-Cline","object":"model","created":1677610602,"owned_by":"openai","connection_type":"external","name":"GPT-OSS-20B-Cline","openai":{"id":"GPT-OSS-20B-Cline","object":"model","created":1677610602,"owned_by":"openai","connection_type":"external"},"urlIdx":0,"actions":[],"filters":[],"tags":[]},"session_id":"a91VsVEKryJM73ioAAAB","chat_id":"386e91ea-56a8-4a34-967f-d3e2b0941e51","id":"3139f820-ee16-4931-856e-562ac703c599","background_tasks":{"title_generation":true,"tags_generation":true,"follow_up_generation":true}}Additional Information
I narrowed the problem area and determined that it is an OWUI bug. I confirmed this by using a different client to submit requests; the requests were logged correctly.
My Docker installation was running version v0.6.25. After detecting the bug, I upgraded to v0.6.26, yet the issue remained.
To rule out environment‑specific factors, I set up a fresh machine with no prior OWUI installation and executed the following command:
DATA_DIR=~/.open-webui uvx --python 3.11 open-webui@latest serve --port 8082@rgaricano commented on GitHub (Sep 4, 2025):
I can see all the log but seem that it have configurated title & tag generation, if it's the case there are one request for each generation (tittle & tags)
@DanielusG commented on GitHub (Sep 4, 2025):
I'm not referring to multiple requests, but rather a single request containing the 'system' field with the system instruction value duplicated – specifically, it appears twice, separated by a newline character (\n), as can be seen in the screenshot.
For the sake of completeness, I will also specify that in the Docker installation, I have disabled the generation of tag titles, etc. The request sent is a single one, and it contains that error.
@rgaricano commented on GitHub (Sep 4, 2025):
Sorry Danielle, but I don't see it.
i only see a json with this info (a normal request):
If you ask about roles system & user messages,
It isn't a bug, It's how, right now, it work: the whole conversation is sended, and those are 2 messages. It's the providers protocol.
Yes, it's a waste of resources and not very logical, which is why history and cache systems are being implemented in this kind of systems and services.
I also hope that in Open-WebUI, at least for locally served models, we can achieve these types of improvements, but with respect to external providers, it will always depend on their protocols.
(maybe I'm offuscated but I can't see any duplicated system and new line in the screenshots provided)
@Ithanil commented on GitHub (Sep 5, 2025):
I also don't reproduce, but because this has been reported before (https://github.com/open-webui/open-webui/issues/16855) I assume there is an actual issue to be reproduced somehow.
@rgaricano I'm still not sure you understood the report. It says the system prompt string gets duplicated inside the system message content. Nothing else.
@DanielusG commented on GitHub (Sep 5, 2025):
I believe the confusion arises from the fact that I added a log that is correctly structured.
In my report you can see that I added three screenshots.
The first image shows what the end user clearly sees and what they expect the provider to receive as a request.
The second screenshot captures the browser’s HTTP request (OpenWebUI frontend → OpenWebUI backend) and shows that the request is correctly formulated and contains no duplicates.
The error occurs during the transition from the OpenWebUI backend to the provider (in this case LiteLLM). As shown in the last screenshot, the system message received by LiteLLM is “You talk as a pirate\nYou talk as a pirate” even though my prompt was simply “You talk as a pirate”.
To reproduce the bug I created a very simple backend that emulates an LLM provider and logs the system prompt received in the terminal.
Steps to reproduce the issue:
fastapianduvicornin a Python environment.Middleware code:
@rgaricano commented on GitHub (Sep 5, 2025):
Ok, now I saw it, ...yes, I was offuscated.
I did tests with dev branch(I was running), and I can't reproduce:
(I edited the dumb server to show more detailed info)
And with main v0.6.26
@DanielusG commented on GitHub (Sep 5, 2025):
Try to set the system prompt manually, it seems like the system prompt from the memory feature right? Try to define a pirate prompt like in my case
@rgaricano commented on GitHub (Sep 5, 2025):
yes, i see
(tested with dev branch)
@rgaricano commented on GitHub (Sep 5, 2025):
The duplication occurs because apply_system_prompt_to_body calls add_or_update_system_message multiple times during request processing.
The fix (as is a small function I put the whole function)
Replace function:
https://github.com/open-webui/open-webui/blob/2407d9b905978d68619bdce4021e424046ec8df9/backend/open_webui/utils/misc.py#L138
by:
now working with the fix:
NOTE:
I didn't made a PR, sure that @tjbck find a better way.
@DanielusG commented on GitHub (Sep 30, 2025):
Any news? For those who heavily use system prompts in OpenWebUI, this bug is extremely penalizing; the models do not respond well to duplicated system prompts. For example, if the prompt were 11k tokens, the provider and the model receive a full 22k of duplicate instructions. it's a critical bug!
@tjbck commented on GitHub (Oct 2, 2025):
Should be addressed with a1fc99c66fc62fcea98cdbef2e23ddbc7a7465b5!