[GH-ISSUE #15569] issue: Multiple Tool Calling with UserValves fails #17604

Closed
opened 2026-04-19 23:24:21 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @SZegotaM on GitHub (Jul 7, 2025).
Original GitHub issue: https://github.com/open-webui/open-webui/issues/15569

Originally assigned to: @tjbck on GitHub.

Check Existing Issues

  • I have searched the existing issues and discussions.
  • I am using the latest version of Open WebUI.

Installation Method

Docker

Open WebUI Version

0.6.15

Ollama Version (if applicable)

No response

Operating System

macOS

Browser (if applicable)

Safari

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

When using two tools each with their own UserValves, I would expect both tool calls to use their respective user valves.

Actual Behavior

When using two tools in a chat, each with their own UserValves, the following error will appear when the second tool call is done:

"'UserValves' object has no attribute "XXX"

Steps to Reproduce

  1. Start with a clean open web ui instance
  2. Add two tools with different User Valves.
  3. Set the UserValves values via the Open Web UI.
  4. Try to call these two tools in one chat with a model (GPT 4.1, native tool calling).
  5. Depending on the order of how the tools are added into the chat, one of the tools will fail to load the UserValves attributes.

Example Tool 1:

import html
import json
import re
from typing import Any, Awaitable, Callable, Dict, List, Optional
import requests
from pydantic import BaseModel, Field, validator
from typing import Literal

class Tools:
class Valves(BaseModel):

    test_valve: int = Field(
        default=4, description="A valve controlling a numberical value"
    )
    choice_option: Literal["choiceA", "choiceB"] = Field(
        default="choiceA",
        description="An example of a multi choice valve",
    )
    priority: int = Field(
        default=0,
        description="Priority level for the filter operations. Lower values are passed through first",
    )
    pass

class UserValves(BaseModel):
    test_user_valve: str = Field(
        default=False,
        description="Test valve",
    )
    pass

def __init__(self):
    self.valves = self.Valves()
    pass

def inlet(self, __user__: dict):
    return __user__["valves"].test_user_valve

Example Tool 2:

import html
import json
import re
from typing import Any, Awaitable, Callable, Dict, List, Optional
import requests
from pydantic import BaseModel, Field, validator
from typing import Literal

class Tools:
class Valves(BaseModel):

    test_valve: int = Field(
        default=4, description="A valve controlling a numberical value"
    )
    choice_option: Literal["choiceA", "choiceB"] = Field(
        default="choiceA",
        description="An example of a multi choice valve",
    )
    priority: int = Field(
        default=0,
        description="Priority level for the filter operations. Lower values are passed through first",
    )
    pass

class UserValves(BaseModel):
    test_user_valve2: str = Field(
        default=False,
        description="Test valve",
    )
    pass

def __init__(self):
    self.valves = self.Valves()
    pass

async def inlet2(self, __user__: dict):
    return __user__["valves"].test_user_valve2

Logs & Screenshots

Image

Additional Information

No response

Originally created by @SZegotaM on GitHub (Jul 7, 2025). Original GitHub issue: https://github.com/open-webui/open-webui/issues/15569 Originally assigned to: @tjbck on GitHub. ### 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 0.6.15 ### Ollama Version (if applicable) _No response_ ### Operating System macOS ### Browser (if applicable) Safari ### 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 When using two tools each with their own UserValves, I would expect both tool calls to use their respective user valves. ### Actual Behavior When using two tools in a chat, each with their own UserValves, the following error will appear when the second tool call is done: "'UserValves' object has no attribute "XXX" ### Steps to Reproduce 1. Start with a clean open web ui instance 2. Add two tools with different User Valves. 3. Set the UserValves values via the Open Web UI. 4. Try to call these two tools in one chat with a model (GPT 4.1, native tool calling). 5. Depending on the order of how the tools are added into the chat, one of the tools will fail to load the UserValves attributes. Example Tool 1: import html import json import re from typing import Any, Awaitable, Callable, Dict, List, Optional import requests from pydantic import BaseModel, Field, validator from typing import Literal class Tools: class Valves(BaseModel): test_valve: int = Field( default=4, description="A valve controlling a numberical value" ) choice_option: Literal["choiceA", "choiceB"] = Field( default="choiceA", description="An example of a multi choice valve", ) priority: int = Field( default=0, description="Priority level for the filter operations. Lower values are passed through first", ) pass class UserValves(BaseModel): test_user_valve: str = Field( default=False, description="Test valve", ) pass def __init__(self): self.valves = self.Valves() pass def inlet(self, __user__: dict): return __user__["valves"].test_user_valve Example Tool 2: import html import json import re from typing import Any, Awaitable, Callable, Dict, List, Optional import requests from pydantic import BaseModel, Field, validator from typing import Literal class Tools: class Valves(BaseModel): test_valve: int = Field( default=4, description="A valve controlling a numberical value" ) choice_option: Literal["choiceA", "choiceB"] = Field( default="choiceA", description="An example of a multi choice valve", ) priority: int = Field( default=0, description="Priority level for the filter operations. Lower values are passed through first", ) pass class UserValves(BaseModel): test_user_valve2: str = Field( default=False, description="Test valve", ) pass def __init__(self): self.valves = self.Valves() pass async def inlet2(self, __user__: dict): return __user__["valves"].test_user_valve2 ### Logs & Screenshots ![Image](https://github.com/user-attachments/assets/b7f957ff-f51f-43ef-8bb5-a5846566ebed) ### Additional Information _No response_
GiteaMirror added the bug label 2026-04-19 23:24:21 -05:00
Author
Owner

@Podden commented on GitHub (Jul 14, 2025):

Stumbled on this as well. I'm using OpenAI Responses API Pipe and when this calls a tool on top, UserValves of the tool get overwritten by the Responses Pipe.

<!-- gh-comment-id:3069518205 --> @Podden commented on GitHub (Jul 14, 2025): Stumbled on this as well. I'm using OpenAI Responses API Pipe and when this calls a tool on top, UserValves of the tool get overwritten by the Responses Pipe.
Author
Owner

@Podden commented on GitHub (Oct 22, 2025):

When I'm calling a pipe with two tools active (eg. Jira and Slack), printing out user["valves"] is always the slack uservalves, regardless if it's printed from a slack method or a Jira method which the LLM has called.

__user__.settings.tools contains all the uservalves of all tools but __user__.valves seems to always contain the values of the last tools selected.

Investigating tools.py from the owui source code, it seems that get_tools is calling **Tools.get_user_valves_by_id_and_user_id only once per request and not per tool call. Maybe there's the culprit? I do not have enough experience to grasp the code ;).

<!-- gh-comment-id:3432471897 --> @Podden commented on GitHub (Oct 22, 2025): When I'm calling a pipe with two tools active (eg. Jira and Slack), printing out `user["valves"]` is always the slack uservalves, regardless if it's printed from a slack method or a Jira method which the LLM has called. `__user__.settings.tools` contains all the `uservalves `of all tools but` __user__.valves` seems to always contain the values of the last tools selected. Investigating` tools.py` from the owui source code, it seems that `get_tools` is calling `**Tools.get_user_valves_by_id_and_user_id `only once per request and not per tool call. Maybe there's the culprit? I do not have enough experience to grasp the code ;).
Author
Owner

@Podden commented on GitHub (Nov 14, 2025):

I think I've fixed it #19185. Please test

<!-- gh-comment-id:3533245271 --> @Podden commented on GitHub (Nov 14, 2025): I think I've fixed it #19185. Please test
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#17604