← Blog

Claude API Tool Use: JSON Schema Validation Guide

2026-10-17 · 5 min read · SubToAPI Team

When you give Claude a tool, you're not handing it a function — you're handing it a JSON Schema. Claude reads that schema to decide what arguments to produce, and the API (or your own code) uses it to check whether the arguments Claude generated are actually valid. If you've landed here, you're probably dealing with one of two problems: Claude is returning tool calls with missing or malformed fields, or you want to validate tool inputs before executing them so a bad call doesn't crash your backend.

The short answer: Claude's tool use follows standard JSON Schema (draft-07-ish subset) for the input_schema field on each tool definition. Claude uses this schema to constrain its output, but it does not guarantee 100% schema-perfect JSON every time — especially with complex nested objects, enums, or optional fields. That means you still need to validate the tool_use payload yourself before you execute anything downstream. Below is how the schema works, what typically goes wrong, and how to build a validation layer that catches issues before they become bugs or security problems.

How Claude Uses input_schema

Every tool you pass to the Messages API looks like this:

{
  "name": "get_weather",
  "description": "Get current weather for a location",
  "input_schema": {
    "type": "object",
    "properties": {
      "location": { "type": "string", "description": "City and country" },
      "unit": { "type": "string", "enum": ["celsius", "fahrenheit"] }
    },
    "required": ["location"]
  }
}

Claude reads input_schema the same way a developer would: type, properties, required, enum, and nested object/array structures are all respected in how it constructs the arguments. When Claude decides to call the tool, it returns a tool_use content block with an input object that should conform to that schema.

In practice, Claude is very good at following simple schemas (flat objects, a handful of string/number/boolean fields) and less reliable as schemas get deeply nested, have many optional fields, or mix types loosely. The model isn't running a JSON Schema validator internally — it's generating tokens that are statistically likely to match the shape you described. That's the gap you need to close in your own code.

Common Validation Failures

A few patterns show up repeatedly when teams build tool-calling agents:

None of these are bugs in Claude per se — they're the expected behavior of a language model approximating a schema. The fix is the same one you'd use for any LLM-generated structured data: validate, then branch.

Building a Validation Layer

The standard approach is to run every tool_use.input through a real JSON Schema validator (Ajv for JavaScript, jsonschema or pydantic for Python) using the exact same schema you sent to Claude. This gives you a deterministic pass/fail instead of trusting the model's output blindly.

import Ajv from "ajv";

const ajv = new Ajv();
const schema = {
  type: "object",
  properties: {
    location: { type: "string" },
    unit: { type: "string", enum: ["celsius", "fahrenheit"] }
  },
  required: ["location"],
  additionalProperties: false
};

const validate = ajv.compile(schema);

function handleToolUse(toolUseBlock) {
  const valid = validate(toolUseBlock.input);
  if (!valid) {
    // return a tool_result with is_error: true and ajv.errors
    return {
      type: "tool_result",
      tool_use_id: toolUseBlock.id,
      content: JSON.stringify(validate.errors),
      is_error: true
    };
  }
  // proceed to execute the real function
}

Feeding validation errors back to Claude as a tool_result with is_error: true is the key move most teams miss. Claude will read the error and typically self-correct on the next turn — re-issuing the tool call with the fixed arguments — instead of you having to retry blindly or fail the whole request.

Schema Design Tips That Reduce Errors

Where SubToAPI Fits

If you're calling Claude's Messages API through SubToAPI, tool definitions and the input_schema format work exactly as documented — SubToAPI is a pass-through layer that gives you an application API key (sub_live_...), streaming, and usage metadata on top of your existing Claude access, not a different tool-calling implementation. You still own the schema design and the validation layer described above; SubToAPI just gives you a stable HTTPS endpoint and dashboard visibility into how often tool calls happen and what they cost. See the tool use docs and the general API docs for request formats, or start from the quickstart if you're setting this up for the first time.

Questions

Does Claude guarantee valid JSON for tool calls? No. Claude is very reliable with simple schemas but can produce malformed or incomplete JSON with complex nested structures. Always validate tool_use.input against your schema before executing.

What JSON Schema features does Claude's input_schema support? A practical subset: type, properties, required, enum, items, nested object/array, and description. Advanced constructs like oneOf/anyOf work less reliably and are best avoided for critical fields.

What should I do when validation fails? Return a tool_result block with is_error: true and the validation error details. Claude will usually read the error and re-issue a corrected tool call on the next turn instead of failing outright.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →