Skip to content

Claude API rejects tool schemas: missing 'required' field causes 'JSON schema is invalid' error #13618

@1186258278

Description

@1186258278

Bug Description

When using OpenCode with Claude models (especially thinking models like claude-opus-4-6-thinking) through an OpenAI-compatible proxy (e.g., new-api), the API returns:

***.custom.input_schema: JSON schema is invalid. It must match JSON Schema draft 2020-12

This happens because some tool schemas generated by plugins (e.g., oh-my-opencode's session_list) have properties but no required field. Claude API strictly requires required to be present when properties exists, even if it's an empty array [].

Steps to Reproduce

  1. Install OpenCode with oh-my-opencode plugin
  2. Configure a custom provider using @ai-sdk/openai-compatible pointing to a new-api instance
  3. Select claude-opus-4-6-thinking as the model
  4. Send any message

Root Cause

Two issues in packages/opencode/src/provider/transform.tsProviderTransform.schema():

1. Missing required field (primary cause)

Plugin tools like session_list generate schemas like:

{
  "type": "object",
  "properties": { "limit": { "type": "number" } },
  "additionalProperties": false
}

Claude API requires required to be present when properties exists. The thinking models are especially strict about this.

2. $schema meta field from Zod 4

Zod 4's toJSONSchema() adds "$schema": "https://json-schema.org/draft/2020-12/schema" to every schema output. While this may not always cause errors, it's a non-standard field for input_schema.

Note: The codebase already handles this for createStructuredOutputTool (line ~687 in prompt.ts: const { $schema, ...toolSchema } = input.schema), but the general ProviderTransform.schema() function doesn't strip it.

Proposed Fix

Add sanitization at the top of ProviderTransform.schema() in packages/opencode/src/provider/transform.ts:

export function schema(model: Provider.Model, schema: JSONSchema.BaseSchema | JSONSchema7): JSONSchema7 {
    // Strip $schema meta field from Zod 4 toJSONSchema() output
    if ("$schema" in schema) {
      const { $schema: _, ...rest } = schema as any
      schema = rest as JSONSchema.BaseSchema
    }

    // Claude API (especially thinking models) requires "required" when "properties" exists
    const s = schema as any
    if (s.type === "object" && s.properties && !s.required) {
      s.required = []
    }

    // ... existing code ...
}

Verification

Tested by intercepting OpenCode's API requests with a proxy, isolating all 33 tools, and testing each individually:

  • session_list with original schema → 400 error
  • session_list with "required": [] added → 200 OK
  • All 33 tools together after fix → 200 OK

Environment

  • OpenCode: v1.2.1
  • oh-my-opencode: v3.5.3
  • Model: claude-opus-4-6-thinking (via new-api OpenAI-compatible proxy)
  • OS: macOS 26.2 (Apple Silicon) / Windows 11

Related

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions