Skip to content

fix: deduplicate required arrays in tool schemas to comply with JSON Schema 2020-12#3025

Closed
saakshigupta2002 wants to merge 1 commit intoComposioHQ:nextfrom
saakshigupta2002:fix/deduplicate-required-schema-entries
Closed

fix: deduplicate required arrays in tool schemas to comply with JSON Schema 2020-12#3025
saakshigupta2002 wants to merge 1 commit intoComposioHQ:nextfrom
saakshigupta2002:fix/deduplicate-required-schema-entries

Conversation

@saakshigupta2002
Copy link
Copy Markdown

Summary

Some tool schemas returned by the Composio API contain duplicate entries in their required arrays, which violates JSON Schema 2020-12 §6.5.3. When these schemas are sent to strict JSON Schema validators — most notably the Anthropic Claude API — the entire tool batch is rejected with:

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

This breaks inference for all users who have affected toolkits connected, not just calls to the specific offending tools. Known affected tools include GITHUB_UPDATE_A_REPOSITORY_VARIABLE and INTERCOM_ATTACH_A_CONTACT_TO_A_COMPANY, though any tool with merged schema variants (via allOf, anyOf, oneOf) could be affected.

This PR adds recursive deduplication of required arrays in both the TypeScript and Python SDKs at the central schema processing layer, ensuring all downstream providers (OpenAI, Anthropic, Vercel, LangChain, etc.) automatically receive compliant schemas without any per-provider changes.

Fixes #2933

Changes

  • TypeScript SDK: Added deduplicateRequiredFields() utility in ts/packages/core/src/utils/jsonSchema.ts that recursively traverses schemas (including nested properties, items, allOf, anyOf, oneOf) and deduplicates any required arrays using [...new Set()]
  • TypeScript SDK: Integrated deduplication into transformToolCases() in ts/packages/core/src/models/Tools.ts so schemas are sanitized immediately when received from the API, before any provider processes them
  • Python SDK: Added equivalent deduplicate_required_fields() utility in python/composio/utils/shared.py using list(dict.fromkeys()) to preserve insertion order while removing duplicates
  • Python SDK: Applied deduplication in both get_raw_composio_tools() and get_raw_composio_tool_by_slug() in python/composio/core/models/tools.py to cover all tool retrieval paths
  • Tests: Added comprehensive test suites for both SDKs covering: basic deduplication, nested schemas, combiners (allOf/anyOf/oneOf), array items, immutability of original input, edge cases (null/undefined), and order preservation

Type of change

  • Bug fix
  • New feature
  • Refactor/Chore
  • Documentation
  • Breaking change

How Has This Been Tested?

TypeScript SDK:

cd ts/packages/core
npx vitest run test/utils/jsonSchema.test.ts
# 8 tests passed covering all deduplication scenarios

Python SDK:

cd python
python -m pytest tests/test_deduplicate_required.py -v
# 9 tests passed covering all deduplication scenarios

Test scenarios include:

  1. Removing duplicates from top-level required arrays
  2. Passing through schemas with no duplicates unchanged
  3. Handling schemas without a required field
  4. Recursive deduplication in nested properties
  5. Deduplication inside allOf, anyOf, and oneOf combiners
  6. Array items schema deduplication
  7. Verifying original schema immutability (no mutation)
  8. Graceful handling of null/undefined/non-dict inputs
  9. Preservation of insertion order when deduplicating

Checklist

  • I have read the Code of Conduct and this PR adheres to it
  • I ran linters/tests locally and they passed
  • I updated documentation as needed
  • I added tests or explain why not applicable
  • I added a changeset if this change affects published packages

Additional context

Root cause: The duplicate required entries likely originate from the backend API's schema generation pipeline, possibly when merging schema variants. This SDK-side fix acts as a defensive layer, ensuring compliance regardless of what the API returns.

Performance impact: Negligible — the deduplication is a lightweight O(n) operation using Set (TS) / dict.fromkeys (Python), applied once per tool schema during retrieval.

Backward compatibility: Fully backward compatible. Schemas without duplicates pass through unchanged. The fix only removes redundant entries that violate the spec.

…Schema 2020-12

Some tool schemas returned by the API contain duplicate entries in their
`required` arrays, violating JSON Schema 2020-12 §6.5.3. This causes
strict validators (e.g. Anthropic Claude API) to reject the entire tool
batch, breaking inference for all users with affected toolkits connected.

Add recursive deduplication of `required` arrays in both TypeScript and
Python SDKs at the central schema processing layer, so all providers
benefit without per-provider changes.

Fixes ComposioHQ#2933
@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 26, 2026

@saakshigupta2002 is attempting to deploy a commit to the Composio Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

tool.input_parameters = deduplicate_required_fields(
tool.input_parameters,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python tool router path missing required field deduplication

Medium Severity

The deduplication fix is applied to get_raw_composio_tools and get_raw_composio_tool_by_slug but not to get_raw_tool_router_meta_tools, which is a third tool retrieval path used by ToolRouterSession.tools(). The TypeScript SDK correctly handles this path because getRawToolRouterMetaTools calls transformToolCases, which applies deduplicateRequiredFields. Tools fetched through the Python tool router session will still carry duplicate required entries and trigger the same Anthropic API rejection this PR aims to fix.

Additional Locations (1)
Fix in Cursor Fix in Web

@haxzie
Copy link
Copy Markdown
Collaborator

haxzie commented Mar 30, 2026

This should ideally be fixed from the tool/api level not SDK level. Thanks for the PR, closing this for now.

@haxzie haxzie closed this Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tool schemas contain duplicate required entries, violating JSON Schema 2020-12

2 participants