Review direct self-references in schema composition

Review references that repeatedly apply a schema to the same data and distinguish intentional recursive models.

Description

A schema that directly references itself in a composition such as allOf can repeatedly apply to the same data, causing circular-resolution errors or excessive expansion in some tools. This does not make every recursive model invalid, such as a tree whose child property has the parent’s type.

Potential impact

Documentation tools or generators may fail to process the model, and validation may take excessive time. Unclear direct recursion can also obscure the intended data contract.

Remediation

Check whether a reference returns to the same schema and data. Remove unnecessary direct references or extract a shared schema, and verify tool support for intentional recursive models. Ensure the resulting constraints preserve the actual contract.

Examples

These OpenAPI 3.0 composition excerpts omit info and paths. The first ExtendedErrorModel references itself directly through allOf.

Before

json
{
  "openapi": "3.0.0",
  "components": {
    "schemas": {
      "ExtendedErrorModel": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ExtendedErrorModel"
          },
          {
            "type": "object",
            "properties": {
              "rootCause": {
                "type": "string"
              }
            }
          }
        ]
      }
    }
  }
}

After

json
{
  "openapi": "3.0.0",
  "components": {
    "schemas": {
      "ErrorModel": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          }
        }
      },
      "ExtendedErrorModel": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ErrorModel"
          },
          {
            "type": "object",
            "properties": {
              "rootCause": {
                "type": "string"
              }
            }
          }
        ]
      }
    }
  }
}

The second refers to a separate ErrorModel, removing the direct cycle. It also adds a message property definition, which should match the actual error model.

References