Skip to content

LoadExternalRefs: false-positive "Circular reference detected" #2872

@alexangas

Description

@alexangas

Firstly please note this is an issue found and reproduced by Claude Code (Opus 4.8).

Describe the bug
When parsing a split-file OpenAPI 3.1 document with LoadExternalRefs = true, the reader throws InvalidOperationException: Circular reference detected while resolving schema: ... for a schema that is not circular.

The trigger is this pattern:

  1. A root document's components/schemas/X entry is itself a pass-through $ref to a schema in an external file (i.e. X: { $ref: './shared.yaml#/X' } — a re-export), and
  2. That same external schema is also referenced directly from somewhere else (e.g. a path operation's response schema).

The resolver appears to treat the root re-export ref plus the direct ref to the same external target as a cycle, even though the target schema is a plain leaf with no outgoing $refs.

OpenApi File To Reproduce

root.yaml

openapi: 3.1.0
info: { title: T, version: 1.0.0 }
paths:
  /a:
    get:
      responses:
        '200':
          description: ok
          content:
            application/json:
              schema:
                type: object
                properties:
                  meta: { $ref: './shared.yaml#/Leaf' }
components:
  schemas:
    Leaf:
      $ref: './shared.yaml#/Leaf'   # root pass-through re-export

shared.yaml

Leaf:
  type: object
  properties:
    x: { type: string }
    y: { type: integer }

Program.cs

using Microsoft.OpenApi;
using Microsoft.OpenApi.Reader;
using Microsoft.OpenApi.YamlReader;

var path = "/abs/path/to/root.yaml";
var settings = new OpenApiReaderSettings { LoadExternalRefs = true, BaseUrl = new Uri(path) };
settings.AddYamlReader();
var result = await OpenApiDocument.LoadAsync(path, settings);
Console.WriteLine($"Paths={result.Document?.Paths?.Count}, Errors={result.Diagnostic?.Errors?.Count}");
System.InvalidOperationException: Circular reference detected while resolving schema: ./shared.yaml#/Leaf

Expected behavior
The document parses successfully. Leaf is a leaf schema with no outgoing references and is not part of any cycle.

Additional context

  • Removing the root components/schemas/Leaf pass-through ref (keeping only the direct ref from the path) parses fine, so the pass-through re-export appears to be the trigger.

  • A leaf schema referenced from multiple paths (but without the root re-export) also parses fine.

  • Microsoft.OpenApi 3.6.0

  • Microsoft.OpenApi.YamlReader 3.6.0

  • net10.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions