Bug Report: qwen3-coder Outputs Tool Call Argument in Incorrect Type for String-Encoded JSON

#21
by bheeee - opened

I encountered an issue where qwen3-coder outputs a tool call argument with an incorrect type.

Specifically, for a tool schema that expects a string value (which contains a JSON string), the model incorrectly outputs it as a JSON object instead of a string.

this is the tool

def write(file:str, content: str)

request example (for openrouter)

{
  "model": "qwen/qwen3-coder",
  "messages": [
    {
      "role": "user",
      "content": "create a pure json content without codeblocks, with field a , a is a string of escaped json object that contains key b , b is string , content is `cccc` and write file 'a.json'"
    }
  ],
  "tools": [
    {
      "name": "Write",
      "description": "Writes a file to the local filesystem.\n\nUsage:\n- This tool will overwrite the existing file if there is one at the provided path.\n- If this is an existing file, you MUST use the Read tool first to read the file's contents. This tool will fail if you did not read the file first.\n- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.\n- NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.\n- Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked.",
      "input_schema": {
        "type": "object",
        "properties": {
          "file_path": {
            "type": "string",
            "description": "The absolute path to the file to write (must be absolute, not relative)"
          },
          "content": {
            "type": "char",
            "description": "The content to write to the file, should be string"
          }
        },
        "required": [
          "file_path",
          "content"
        ],
        "additionalProperties": false,
      }
    }
  ],
  "max_tokens": 4200
}

Expected response

{'choices': [{'message': {'role': 'assistant', 'content': '', 'tool_calls': [{'name': 'Write', 'arguments': '{"content": "{\\"pattern\\": \\"package\\", \\"path\\": \\"/xxx/ClientExample.java\\"}", "file_path": "a.json"}'}]}}]}
{"value": "{\n  \"a\": \"b\"\n}"}

actual output

{'choices': [{'message': {'role': 'assistant', 'content': '', 'tool_calls': [{'name': 'Write', 'arguments': '{"content": {"pattern": "package", "path": "/Users/qixiang/Projects/solutions/testmcp/src/main/java/com/tpp/solution/CallTpp/TppClientExample.java"}, "file_path": "a.json"}'}]}}]}

Note: The content field is parsed into an object, which violates the tool's schema that defines content as a string.
๐Ÿ” Root Cause (Suspected)

In the parser code (screenshot below), it seems that string fields are not validated for type correctness โ€” if the content looks like a JSON object, param value is deserialized, and the parsing code will return directly, will value type converting

For fields of type object, this behavior is correct. 

ๅ›พ็‰‡.png

But for fields explicitly defined as string, the parser ignores value type validating โ€” it should make sure the raw string form.

ๅ›พ็‰‡.png

bheeee changed discussion status to closed

Sign up or log in to comment