Skip to content

Recursive $ref crashes generation for OpenAPI and AsyncAPI input #447

Description

@jonaslagoni

Summary

A self-referencing $ref in the input document makes generation fail. It affects OpenAPI and AsyncAPI input with different errors, while the same recursive schema through JSON Schema input generates fine.

Version: 0.81.1. Also reproduces on main.

Reproduction

OpenAPI — Converting circular structure to JSON

api.yaml:

openapi: 3.0.3
info:
  title: Recursive
  version: 1.0.0
paths:
  /nodes:
    get:
      operationId: getNode
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Node'
components:
  schemas:
    Node:
      type: object
      required: [label]
      properties:
        label:
          type: string
        children:
          type: array
          items:
            $ref: '#/components/schemas/Node'

codegen.config.js:

export default {
  inputType: 'openapi',
  inputPath: './api.yaml',
  language: 'typescript',
  generators: [{preset: 'payloads', outputPath: './out'}]
};
$ npx @the-codegen-project/cli@0.81.1 generate ./codegen.config.js
Generating code...
✗ Generation failed

Error: Generator 'generate' failed

Details:
Converting circular structure to JSON
    --> starting at object with constructor 'Object'
    |     property 'children' -> object with constructor 'Object'
    |     property 'items' -> object with constructor 'Object'
    --- property 'properties' closes the circle

AsyncAPI — Could not dereference $ref in input

The same recursive schema in an AsyncAPI v3 document fails differently:

asyncapi: 3.0.0
info:
  title: Recursive
  version: 1.0.0
channels:
  nodes:
    address: nodes
    messages:
      Node:
        payload:
          $ref: '#/components/schemas/Node'
operations:
  sendNode:
    action: send
    channel:
      $ref: '#/channels/nodes'
components:
  schemas:
    Node:
      type: object
      required: [label]
      properties:
        label:
          type: string
        children:
          type: array
          items:
            $ref: '#/components/schemas/Node'
Details:
Could not dereference $ref in input, is all the references correct? 1 error occurred while reading '<cwd>'

Deleting only the children property from that same document generates successfully, so the failure is the recursion and not the surrounding document.

JSON Schema input — works

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Node",
  "type": "object",
  "required": ["label"],
  "properties": {
    "label": {"type": "string"},
    "children": {"type": "array", "items": {"$ref": "#"}}
  }
}
✓ Generated 1 file in 5ms

Modelina handles the recursion; the break is upstream of it, in the OpenAPI/AsyncAPI input processing.

Expected

Recursive $ref should generate a self-referencing model, as it already does for JSON Schema input and as openapi-generator, Kiota and @hey-api/openapi-ts all do for OpenAPI (each emits children?: Node[]).

Notes

Recursive structures are common in real documents — category trees, comment threads, nested rule/filter expressions, JSON-Schema-shaped payloads.

Found while building https://github.com/the-codegen-project/comparisons. documents/openapi/complex.yaml there contains a recursive EvidenceNode, and the listDisputes operation had to be excluded via filter to keep generation working:
https://github.com/the-codegen-project/comparisons/blob/main/comparisons/the-codegen-project/openapi/codegen.complex.config.js

The two different error messages suggest two separate fixes: the OpenAPI path serializes the processed schema with JSON.stringify somewhere it should not, and the AsyncAPI path fails during $ref dereferencing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions