Skip to content

fix(infer): raise the intended ValueError when tool_choice names an unknown tool - #10250

Merged
hjh0119 merged 1 commit into
modelscope:mainfrom
Lesereingrape:fix/tool-choice-not-found
Sep 28, 2026
Merged

hjh0119 merged 1 commit into
modelscope:mainfrom
Lesereingrape:fix/tool-choice-not-found

Conversation

@Lesereingrape

Copy link
Copy Markdown
Contributor

PR type

  • Bug Fix
  • Feature
  • Others

PR information

A swift deploy server answers HTTP 500 Internal Server Error for a request that selects a tool which is not in tools, even though the code has a message prepared for exactly that case.

ChatCompletionRequestMixin.__post_init__ filters the tool list by name:

name = self.tool_choice['function']['name']
tool = next(tool for tool in self.tools if tool['function']['name'] == name)
if tool is None:
    raise ValueError(f"Tool choice '{name}' not found in tools.")
self.tools = [tool]

next(generator) with no default raises StopIteration as soon as the generator is exhausted, so tool is never None and the ValueError below it is unreachable. __post_init__ runs while the request object is being built, i.e. before create_chat_completion (swift/pipelines/infer/deploy.py:272) gets a chance to run its own except Exception → 400 handler, so the exception escapes the handler entirely.

Measured on the current main (5256c62e), constructing the request directly:

File "swift/infer_engine/protocol.py", line 250, in __post_init__
    tool = next(tool for tool in self.tools if tool['function']['name'] == name)
StopIteration

and end to end, with a FastAPI app that registers the same create_chat_completion(request: ChatCompletionRequest, raw_request: Request) signature as deploy.py:272 and a body of {"model": "m", "messages": [...], "tools": [{"type": "function", "function": {"name": "get_weather"}}], "tool_choice": {"type": "function", "function": {"name": "no_such_tool"}}}:

  • before the fix: 500 Internal Server Error, body Internal Server Error — the client is told nothing about what it sent wrong;
  • after the fix: 422 with {"type": "value_error", ..., "msg": "Value error, Tool choice 'no_such_tool' not found in tools."} — the message the author wrote.

tool_choice naming a specific function is part of the OpenAI chat-completions request format that this endpoint is compatible with, so a client that misspells a tool name is a normal case, not a crafted one. A wrong name should not look like a server fault.

The fix is one argument: give next() the default the following if already expects.

tool = next((tool for tool in self.tools if tool['function']['name'] == name), None)

Tested with the new tests/general/test_protocol_tool_choice.py, which pins the failing case plus two cases that must keep working (a name that is in tools narrows request.tools to just that tool; a string tool_choice such as 'auto' leaves the list untouched):

  • on main before the fix: Ran 3 tests ... FAILED (errors=1), the error being the StopIteration above;
  • after the fix: Ran 3 tests ... OK, and the same route probe now returns the 422/ValueError message;
  • flake8, isort --check-only and yapf --diff report nothing on either file.

Disclosure: this PR was prepared, tested and submitted by an AI agent working on behalf of the account owner.

@hjh0119
hjh0119 merged commit ad2f1cb into modelscope:main Sep 28, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants