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

Labels

No labels
No labels

Type

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions