langchain · difficulty ◆◆◆
Tool Schemas with Unsupported Top-Level Composition (langchain-anthropic 1.5.4)
Fail fast on schemas Anthropic cannot express - before your tool call blows up in production.
Your Pydantic Union is a tool schema that Anthropic simply cannot understand - and now you find out immediately.
$ pip install -U langchain-anthropic==1.5.4What it does
Anthropic\u2019s tool-calling API accepts schemas describing the function calls a model can make. When a schema uses top-level composition patterns - a root oneOf, an allOf, or a bare array type without an items key - older langchain-anthropic would silently drop those fields, raise an opaque validation error, or send a malformed schema that fails at runtime. The fix in langchain-anthropic==1.5.4 (PR #39273) intercepts these unsupported patterns before serialization: it either flattens them into a compatible form or raises a clear, actionable error upfront.
Why it matters
When you bind tools for Claude via bind_tools or the @tool decorator, LangChain converts your Python signatures into JSON schemas for Anthropic. Real projects use Pydantic models with discriminated unions (oneOf), optional composition (allOf), or bare list types at the top level - valid in LangChain\u2019s internal schema system but unsupported by Anthropic. Before this fix you only discovered the mismatch when a specific tool was actually called, producing confusing runtime errors. Now the failure surfaces at schema-build time with a clear message, saving hours of production debugging.
Example
$ Bind a Pydantic model with a top-level Union and see the new upfront behaviorSchema validation passed — tools bound successfully
Tool call result: AIMessage(content='...' additional_kwargs={'tool_calls': [...]})When the schema contains an unrecoverable pattern, you now get: Schema error (now clear upfront): Unsupported top-level composition in tool schema for 'SearchTool': top-level 'oneOf' is not supported by Anthropic. Consider flattening the schema or using a root 'object' type.
$ Inspect which schema shapes trigger the guardclass SearchTool(BaseModel):
query: str
filter: Union[str, int, None] = None # top-level oneOf
class BatchIDs(BaseModel):
ids: list # bare list, no items=
# Both now fail or flatten at bind time, not at call timeCommon flags
- #39273
- fix(anthropic): handle tool schemas with unsupported top-level composition.
- bind_tools
- Binds Pydantic/tool schemas to a Claude model for tool calling.
- convert_to_anthropic_tool_schema
- Converts a LangChain schema to Anthropic\u2019s expected JSON format.
History
Schema dialects rarely match
LangChain\u2019s internal schema model is richer than what any single provider accepts. Anthropic\u2019s tool spec, in particular, does not support root-level composition keywords. For a long time the gap was only discovered lazily, at runtime. The 1.5.4 fix adds an eager validation pass, shifting the failure left in the development cycle - the classic win of fail-fast validation over fail-late.
Fun facts
Pros & cons
pros
- + Fail-fast schema validation
- + Clear, actionable error messages
- + Flattens compatible patterns automatically
cons
- − Some schemas need manual refactoring
- − Anthropic-specific; other providers differ
Takeaways
- 1Bind tools inside a try/except that logs the schema.
- 2Prefer root-object schemas with named properties for Anthropic.
- 3Upgrade to langchain-anthropic>=1.5.4 to get eager validation.