Skip to content

$ref changes are dropped when a document has any circular reference #662

Closed

Description

@josephaxisa

If a document contains any circular reference, CheckSchemaProxyForCircularRefs returns true for every schema proxy, including ones that are not part of the loop. CompareSchemas then returns nil in its $ref branches, so changes to those schemas are not reported at all.

# old.yaml
openapi: 3.0.3
info: {title: t, version: '1'}
paths: {}
components:
  schemas:
    Owner:
      type: object
      properties:
        pet:
          $ref: '#/components/schemas/Pet'
    Pet:
      type: object
      properties:
        name: {type: string}
    A:
      type: object
      properties:
        b: {$ref: '#/components/schemas/B'}
    B:
      type: object
      properties:
        a: {$ref: '#/components/schemas/A'}

new.yaml is the same, except Owner.pet is inlined and requires name:

        pet:
          type: object
          properties:
            name: {type: string}
          required: [name]

openapi-changes report old.yaml new.yaml reports no changes. Remove A and B from both files and it reports the $ref change.

The cause is that the journey check (source) keeps one dup map across all circular references and returns true on any repeated entry, without comparing it to s. A journey always repeats its loop point (B -> A -> B), so the first circular reference makes the function return true.

A fix needs care. The dup check is currently also what stops QuickHash from recursing through cross-file cycles. A relative $ref such as b.yaml#/B doesn't match the journey's Definition or FullDefinition, so a narrower check that compares s.GetReference() hangs on those documents. A journey also includes the path leading into the loop, not just the loop itself. So the check probably needs to compare the proxy's resolved full definition against Journey[LoopIndex:]. Does that direction make sense to you? Happy to work on a PR once we agree on the approach.

Related to #663

Activity

  1. josephaxisa commented on Oct 22, 2026

    @josephaxisa
    ContributorAuthor

    @daveshanley I worked out a node-based loop-tail check that handles cross-file cycles cleanly and keeps inline schemas out of the circular set under UseSchemaQuickHash. Opened in #667 whenever you have a moment to review.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions