-
Notifications
You must be signed in to change notification settings - Fork 609
Open
Description
Checklist
- 1. I have searched related issues but cannot get the expected help.
- 2. The bug has not been fixed in the latest version.
- 3. Please note that if the bug-related issue you submitted lacks corresponding environment info and a minimal reproducible demo, it will be challenging for us to reproduce and resolve the issue, reducing the likelihood of receiving feedback.
Describe the bug
When processing chat messages from models like Qwen or GPT-OSS that return tool calls, the assistant message may have a tool_calls
field but no content
field (or content: null
). This causes a KeyError
when the code tries to check isinstance(msg['content'], list)
.
Reproduction
- Start an LMDeploy server with Qwen3-8B:
lmdeploy serve api_server Qwen/Qwen3-8B --tool-call-parser qwen3
- Send a chat completion request with tool calling:
from openai import OpenAI
client = OpenAI(
api_key='EMPTY',
base_url='http://localhost:23333/v1'
)
model = 'Qwen/Qwen3-8B'
# Define a simple weather tool
tools = [{
'type': 'function',
'function': {
'name': 'get_weather',
'description': 'Get the current weather for a location',
'parameters': {
'type': 'object',
'properties': {
'location': {
'type': 'string',
'description': 'The city name, e.g. San Francisco'
}
},
'required': ['location']
}
}
}]
# Initial user request
messages = [
{'role': 'user', 'content': 'What is the weather like in Paris?'}
]
response = client.chat.completions.create(
model=model,
messages=messages,
tools=tools,
)
# The assistant responds with a tool call
assistant_message = response.choices[0].message
print(assistant_message)
# Output shows:
# {
# 'role': 'assistant',
# 'content': None, # or missing entirely
# 'tool_calls': [{
# 'id': 'call_abc123',
# 'type': 'function',
# 'function': {
# 'name': 'get_weather',
# 'arguments': '{"location": "Paris"}'
# }
# }]
# }
# Now append the assistant message and tool result to continue the conversation
messages.append({
'role': 'assistant',
'tool_calls': assistant_message.tool_calls
# Note: 'content' field is missing or None
})
messages.append({
'role': 'tool',
'tool_call_id': assistant_message.tool_calls[0].id,
'content': '{"temperature": 18, "condition": "sunny"}'
})
# Send the follow-up request - this triggers the bug!
response = client.chat.completions.create(
model=model,
messages=messages
)
BUG ANALYSIS: In lmdeploy/serve/async_engine.py
, the code directly accesses msg['content']
without checking if the field exists:
if isinstance(prompt, list) and any(isinstance(msg['content'], list) for msg in prompt):
Environment
/bin/sh: 1: /usr/local/cuda/bin/nvcc: not found
/bin/sh: 1: gcc: not found
sys.platform: linux
Python: 3.11.13 (main, Jun 5 2025, 13:12:00) [GCC 11.2.0]
CUDA available: True
MUSA available: False
numpy_random_seed: 2147483648
GPU 0,1,2,3: Tesla V100-SXM2-16GB
CUDA_HOME: /usr/local/cuda
NVCC: Not Available
GCC: n/a
PyTorch: 2.8.0+cu128
PyTorch compiling details: PyTorch built with:
- GCC 13.3
- C++ Version: 201703
- Intel(R) oneAPI Math Kernel Library Version 2024.2-Product Build 20240605 for Intel(R) 64 architecture applications
- Intel(R) MKL-DNN v3.7.1 (Git Hash 8d263e693366ef8db40acc569cc7d8edf644556d)
- OpenMP 201511 (a.k.a. OpenMP 4.5)
- LAPACK is enabled (usually provided by MKL)
- NNPACK is enabled
- CPU capability usage: AVX2
- CUDA Runtime 12.8
- NVCC architecture flags: -gencode;arch=compute_70,code=sm_70;-gencode;arch=compute_75,code=sm_75;-gencode;arch=compute_80,code=sm_80;-gencode;arch=compute_86,code=sm_86;-gencode;arch=compute_90,code=sm_90;-gencode;arch=compute_100,code=sm_100;-gencode;arch=compute_120,code=sm_120
- CuDNN 91.0.2 (built against CUDA 12.9)
- Built with CuDNN 90.8
- Magma 2.6.1
- Build settings: BLAS_INFO=mkl, BUILD_TYPE=Release, COMMIT_SHA=a1cb3cc05d46d198467bebbb6e8fba50a325d4e7, CUDA_VERSION=12.8, CUDNN_VERSION=9.8.0, CXX_COMPILER=/opt/rh/gcc-toolset-13/root/usr/bin/c++, CXX_FLAGS= -fvisibility-inlines-hidden -DUSE_PTHREADPOOL -DNDEBUG -DUSE_KINETO -DLIBKINETO_NOROCTRACER -DLIBKINETO_NOXPUPTI=ON -DUSE_FBGEMM -DUSE_PYTORCH_QNNPACK -DUSE_XNNPACK -DSYMBOLICATE_MOBILE_DEBUG_HANDLE -O2 -fPIC -DC10_NODEPRECATED -Wall -Wextra -Werror=return-type -Werror=non-virtual-dtor -Werror=range-loop-construct -Werror=bool-operation -Wnarrowing -Wno-missing-field-initializers -Wno-unknown-pragmas -Wno-unused-parameter -Wno-strict-overflow -Wno-strict-aliasing -Wno-stringop-overflow -Wsuggest-override -Wno-psabi -Wno-error=old-style-cast -faligned-new -Wno-maybe-uninitialized -fno-math-errno -fno-trapping-math -Werror=format -Wno-dangling-reference -Wno-error=dangling-reference -Wno-stringop-overflow, LAPACK_INFO=mkl, PERF_WITH_AVX=1, PERF_WITH_AVX2=1, TORCH_VERSION=2.8.0, USE_CUDA=ON, USE_CUDNN=ON, USE_CUSPARSELT=1, USE_GFLAGS=OFF, USE_GLOG=OFF, USE_GLOO=ON, USE_MKL=ON, USE_MKLDNN=ON, USE_MPI=OFF, USE_NCCL=1, USE_NNPACK=ON, USE_OPENMP=ON, USE_ROCM=OFF, USE_ROCM_KERNEL_ASSERT=OFF, USE_XCCL=OFF, USE_XPU=OFF,
TorchVision: 0.23.0+cu128
LMDeploy: 0.10.1+unknown
transformers: 4.56.2
fastapi: 0.117.1
pydantic: 2.11.9
triton: 3.4.0
NVIDIA Topology:
GPU0 GPU1 GPU2 GPU3 CPU Affinity NUMA Affinity GPU NUMA ID
GPU0 X NV2 NV2 NV2 0,2,4,6,8,10 0 N/A
GPU1 NV2 X NV2 NV2 0,2,4,6,8,10 0 N/A
GPU2 NV2 NV2 X NV2 0,2,4,6,8,10 0 N/A
GPU3 NV2 NV2 NV2 X 0,2,4,6,8,10 0 N/A
Legend:
X = Self
SYS = Connection traversing PCIe as well as the SMP interconnect between NUMA nodes (e.g., QPI/UPI)
NODE = Connection traversing PCIe as well as the interconnect between PCIe Host Bridges within a NUMA node
PHB = Connection traversing PCIe as well as a PCIe Host Bridge (typically the CPU)
PXB = Connection traversing multiple PCIe bridges (without traversing the PCIe Host Bridge)
PIX = Connection traversing at most a single PCIe bridge
NV# = Connection traversing a bonded set of # NVLinks
Error traceback
2025-10-11 14:08:43,577 - lmdeploy - INFO - turbomind.py:773 - [async_stream_infer] session 5 done
2025-10-11 14:08:43,577 - lmdeploy - INFO - async_engine.py:879 - session 5 finished, reason "stop", input_tokens 162, output_tokens 21
INFO: 127.0.0.1:41294 - "POST /v1/chat/completions HTTP/1.1" 200 OK
INFO: 127.0.0.1:41294 - "POST /v1/chat/completions HTTP/1.1" 500 Internal Server Error
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/uvicorn/protocols/http/h11_impl.py", line 403, in run_asgi
result = await app( # type: ignore[func-returns-value]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 60, in __call__
return await self.app(scope, receive, send)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/fastapi/applications.py", line 1082, in __call__
await super().__call__(scope, receive, send)
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/starlette/applications.py", line 113, in __call__
await self.middleware_stack(scope, receive, send)
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/starlette/middleware/errors.py", line 186, in __call__
raise exc
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/starlette/middleware/errors.py", line 164, in __call__
await self.app(scope, receive, _send)
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/starlette/middleware/cors.py", line 85, in __call__
await self.app(scope, receive, send)
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 63, in __call__
await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
raise exc
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
await app(scope, receive, sender)
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/starlette/routing.py", line 716, in __call__
await self.middleware_stack(scope, receive, send)
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/starlette/routing.py", line 736, in app
await route.handle(scope, receive, send)
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/starlette/routing.py", line 290, in handle
await self.app(scope, receive, send)
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/starlette/routing.py", line 78, in app
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
raise exc
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
await app(scope, receive, sender)
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/starlette/routing.py", line 75, in app
response = await f(request)
^^^^^^^^^^^^^^^^
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/fastapi/routing.py", line 308, in app
raw_response = await run_endpoint_function(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/fastapi/routing.py", line 219, in run_endpoint_function
return await dependant.call(**values)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/lmdeploy/serve/openai/api_server.py", line 572, in chat_completions_v1
async for res in result_generator:
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/lmdeploy/serve/async_engine.py", line 730, in generate
prompt_input = await self._get_prompt_input(prompt,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/lmdeploy/serve/async_engine.py", line 612, in _get_prompt_input
if isinstance(prompt, list) and any(isinstance(msg['content'], list) for msg in prompt):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/ma/lmdeploy-0.10.1/lib/python3.11/site-packages/lmdeploy/serve/async_engine.py", line 612, in <genexpr>
if isinstance(prompt, list) and any(isinstance(msg['content'], list) for msg in prompt):
~~~^^^^^^^^^^^
KeyError: 'content'
Metadata
Metadata
Assignees
Labels
No labels