Skip to content

Anthropic 400: tools.N.custom.input_schema.type Field required (tool schema missing top-level type) #75

Description

@seotk0319

요약 / Summary

Anthropic(Claude) 백엔드로 사용할 때, Codex가 서브에이전트/브라우저/코덱스 툴 등 추가 툴을 붙이는 순간 아래 400이 발생합니다.

Provider error 400: {"type":"error","error":{"type":"invalid_request_error","message":"tools.26.custom.input_schema.type: Field required"},"request_id":"req_011CcqiYNzcinns1gsUkV9Cg"}

When using an Anthropic (Claude) backend, requests fail as soon as extra tools are attached (sub-agent, browser use, Codex tools). Anthropic rejects a tool whose input_schema lacks a top-level type.

환경 / Environment

  • Package: @bitkyc08/opencodex@2.6.31-preview.20260707 (same code path exists upstream)
  • OS: Windows
  • Backend: Anthropic (Claude Opus)
  • Trigger: only when the tool list grows (sub-agent / browser / Codex tools). Basic chat without those tools works fine.

원인 / Root cause

src/adapters/anthropic.ts 의 toolsToAnthropicFormat 가 input_schema 로 t.parameters 를 그대로 전달합니다. 일부 Codex/MCP/서브에이전트/브라우저 툴의 파라미터 스키마에는 최상위 type: "object" 가 없습니다. OpenAI 와이어는 이를 허용하지만 Anthropic Messages API 는 input_schema.type 을 필수로 검증하므로 400 을 반환합니다.

toolsToAnthropicFormat passes t.parameters straight through as input_schema. Some Codex/MCP/sub-agent/browser tools ship a parameter schema without a top-level type: "object". The OpenAI wire tolerates this, but the Anthropic Messages API requires input_schema.type, so it 400s. The failing index (e.g. tools.26) is one of the extra tools, which is why plain chat works but adding tools breaks.

const converted = tools.map(t => ({
  name: toolNames.toWire(namespacedToolName(t.namespace, t.name)),
  description: t.description,
  input_schema: t.parameters, // <- schema without top-level `type` is forwarded verbatim
}));

제안 수정 / Proposed fix

input_schema 를 Anthropic 요구사항에 맞게 정규화합니다 (최상위 type 누락 시 object 보정 + properties 보장).

// Anthropic requires every tool's `input_schema` to be a JSON Schema object with an
// explicit top-level `type` (it validates `tools.N.custom.input_schema.type`). Codex/
// OpenAI Responses tool params frequently omit it, which the OpenAI wire tolerates but
// Anthropic 400s on. Normalize so a missing/invalid top-level `type` becomes an object
// schema with `properties`.
function normalizeAnthropicInputSchema(schema: unknown): Record<string, unknown> {
  if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
    return { type: "object", properties: {} };
  }
  const s: Record<string, unknown> = { ...(schema as Record<string, unknown>) };
  if (typeof s.type !== "string") s.type = "object";
  if (s.type === "object" && (s.properties === undefined || s.properties === null)) {
    s.properties = {};
  }
  return s;
}

// ...in toolsToAnthropicFormat:
input_schema: normalizeAnthropicInputSchema(t.parameters),

재현 / Reproduction

  1. Configure an Anthropic (Claude) backend.
  2. In Codex, trigger a sub-agent, browser use, or Codex tools so the tool list grows.
  3. Request 400s with tools.N.custom.input_schema.type: Field required.

로컬에서 위 패치 적용 후 서브에이전트/브라우저/코덱스 툴 호출이 정상 동작하는 것을 확인했습니다. Verified locally: after applying the patch, sub-agent/browser/Codex tool calls work. Happy to open a PR if the approach looks good.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions