Bug Description
Tools with typed parameters (array, object, number, boolean) fail with Zod validation error when the LLM sends the parameter as a string instead of the proper type.
Error Examples
Case 1: Array as string (Todowrite)
⚙ Todowrite [todos=[{"id": "1", "content": "Database: Migration", "status": "completed", "priority": "high"}, ...]]
Error: The Todowrite tool was called with invalid arguments: [
{
"expected": "array",
"code": "invalid_type",
"path": ["todos"],
"message": "Invalid input: expected array, received string"
}
]
Case 2: Number as string (Bash timeout)
⚙ Bash [command=pnpm build 2>&1 | head -100, description=Build project to verify i18n fixes, timeout=180000]
Error: The Bash tool was called with invalid arguments: [
{
"expected": "number",
"code": "invalid_type",
"path": ["timeout"],
"message": "Invalid input: expected number, received string"
}
]
Root Cause
LLMs sometimes serialize typed parameters as strings:
{ "todos": "[{...}]" } instead of { "todos": [{...}] }
{ "timeout": "180000" } instead of { "timeout": 180000 }
{ "enabled": "true" } instead of { "enabled": true }
Affected Tools
| Tool |
Parameter |
Type |
| Todowrite |
todos |
array |
| Question |
questions |
array |
| Bash |
timeout |
number |
| Webfetch |
timeout |
number |
| Websearch |
numResults |
number |
| LSP tools |
line, character |
number |
| Edit |
replaceAll |
boolean |
| Multiedit |
replaceAll |
boolean |
Proposed Fix
Add automatic coercion in Tool.define():
- If validation fails with type mismatch, attempt to coerce string values
- For strings starting with
[ or {: try JSON.parse()
- For numeric strings: convert with
Number()
- For "true"/"false": convert to boolean
- Retry validation with coerced values
- Backward compatible: if coercion fails, throw original error
Environment
- OpenCode version: 1.1.8
- All providers affected (Anthropic, OpenAI, Google, etc.)
Bug Description
Tools with typed parameters (array, object, number, boolean) fail with Zod validation error when the LLM sends the parameter as a string instead of the proper type.
Error Examples
Case 1: Array as string (Todowrite)
Case 2: Number as string (Bash timeout)
Root Cause
LLMs sometimes serialize typed parameters as strings:
{ "todos": "[{...}]" }instead of{ "todos": [{...}] }{ "timeout": "180000" }instead of{ "timeout": 180000 }{ "enabled": "true" }instead of{ "enabled": true }Affected Tools
Proposed Fix
Add automatic coercion in
Tool.define():[or{: tryJSON.parse()Number()Environment