Repository navigation
Cut cyclic $refs instead of leaving them dangling - #14
Merged
Merged
Conversation
resolve_refs left a $ref in place when it hit a cycle. FastMCP moves the
schema into a tool's $defs, where that $ref points nowhere, so every call
to the tool failed argument validation with PointerToNowhere. springdoc
emits every polymorphic type as such a cycle (the parent lists subtypes in
oneOf, each subtype extends the parent through allOf), so this broke any
tool whose input includes one, such as createOrUpdateWorkflow and
runWorkflow.
Re-expand a cyclic ref once without its oneOf/anyOf/discriminator, so a
subtype keeps the fields it inherits, and replace any deeper repeat with a
{"type": ...} placeholder.
hannavigil
approved these changes
Sep 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 Claude here, on Arek's behalf:
What
resolve_refsleft a$refin place when it hit a cycle. FastMCP moves each tool's input schema into$defs, where that$refpoints to nothing, so every call to the tool failed argument validation:springdoc writes every polymorphic type as such a cycle: the parent lists its subtypes in
oneOf, and each subtype extends the parent throughallOf. So any tool whose input contains one is broken. The first two arecreateOrUpdateWorkflowandrunWorkflow.Fix
oneOf/anyOf/discriminator. A subtype keeps the fields it inherits from the parent, such as thetypediscriminator.{"type": ...}placeholder (with the description, if there is one).#/components/schemas/...$refis left in a resolved path.Verification
pytest tests --ignore=tests/integration --ignore=tests/manual: 27 passed.test_resolve_circular_refsasserted the old behavior (ref preserved), so I changed it.test_resolve_polymorphic_refsis new.swagger.jsonget exactly the same input schemas: 53,509 bytes before and after.createOrUpdateWorkflowwent from 68 to 0.createOrUpdateWorkflow(create + replace),runWorkflow,getWorkflowRunand the permission 403s all work end to end.Worth knowing
With its subtypes inlined, the
createOrUpdateWorkflowinput schema is about 89 KB. It works, but it is large for an agent's tool list.