Skip to content

ool arguments with stringified JSON arrays/objects fail Zod validation #8249

Closed as duplicate

Description

@kruxigt

Description

When AI models output tool arguments with nested arrays/objects as JSON strings instead of actual JSON structures, tool validation fails. This is a known behavior where some models double-encode nested JSON.

Steps to Reproduce

  1. Use the question tool (AskUserQuestion)
  2. Model outputs arguments like:

{
"questions": "[{"question": "What did you mean?", "header": "Clarify", "options": [...]}]"
}

  1. Validation fails because questions is a string, not an array

Expected Behavior

The tool should detect and parse stringified JSON before Zod validation.

Actual Behavior

Error: The question tool was called with invalid arguments: [
{
"expected": "array",
"code": "invalid_type",
"path": ["questions"],
"message": "Invalid input: expected array, received string"
}
]

The model retries repeatedly with the same format, causing a loop.

Proposed Fix

In packages/opencode/src/tool/tool.ts, add a helper to parse stringified JSON before validation:

function parseStringifiedJson(value: unknown): unknown {
if (typeof value === "string") {
const trimmed = value.trim()
if ((trimmed.startsWith("[") && trimmed.endsWith("]")) ||
(trimmed.startsWith("{") && trimmed.endsWith("}"))) {
try {
return parseStringifiedJson(JSON.parse(trimmed))
} catch {
return value
}
}
return value
}

if (Array.isArray(value)) {
  return value.map(parseStringifiedJson)
}

if (value !== null && typeof value === "object") {
  const result: Record<string, unknown> = {}
  for (const [key, val] of Object.entries(value)) {
    result[key] = parseStringifiedJson(val)
  }
  return result
}

return value

}

Then in Tool.define() around line 56:

toolInfo.execute = async (args, ctx) => {
const fixedArgs = parseStringifiedJson(args) // Add this
try {
toolInfo.parameters.parse(fixedArgs)
} catch (error) {
// ...
}
const result = await execute(fixedArgs, ctx)
// ...
}

Environment

  • OpenCode version: latest
  • Model: Claude (Anthropic API)
  • Affected tools: question (and potentially any tool with nested array/object params)

Additional Context

This is a common issue with LLM tool use where models sometimes serialize nested structures as strings rather than native JSON. Other frameworks handle this by detecting and parsing stringified JSON before schema validation.

Activity

  1. github-actions commented on Jan 13, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    Feel free to ignore if none of these address your specific case.

  2. kruxigt commented on Jan 13, 2026

    @kruxigt
    Author

    This issue might be a duplicate of existing issues. Please check:

    Feel free to ignore if none of these address your specific case.

    It probably is! Sorry

  3. rekram1-node commented on Jan 13, 2026

    @rekram1-node
    Contributor

    What model are you getting this with tho? Most models should be smart enough to do this

  4. kruxigt commented on Jan 13, 2026

    @kruxigt
    Author
  5. i-m-sid commented on Feb 18, 2026

    @i-m-sid
    Contributor

    getting the same issue with claude models

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions