{"record":{"id":"55f6399815607de2","repo":"microsoft/semantic-kernel","slug":"max-level-openapiparser-payload-properties-hierar","errorCode":null,"errorMessage":"Max level {OpenApiParser.PAYLOAD_PROPERTIES_HIERARCHY_MAX_DEPTH} of traversing payload properties of `{operation_id}` operation is exceeded.","messagePattern":"Max level (.+?) of traversing payload properties of `(.+?)` operation is exceeded\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/connectors/openapi_plugin/openapi_parser.py","lineNumber":107,"sourceCode":"            result.append(\n                RestApiParameter(\n                    name=name,\n                    type=schema.get(\"type\", \"string\") if schema else \"string\",\n                    location=location,\n                    description=description,\n                    is_required=is_required,\n                    default_value=default_value,\n                    schema=schema if schema else {\"type\": \"string\"},\n                )\n            )\n        return result\n\n    def _get_payload_properties(self, operation_id, schema, required_properties, level=0):\n        if schema is None:\n            return []\n\n        if level > OpenApiParser.PAYLOAD_PROPERTIES_HIERARCHY_MAX_DEPTH:\n            raise Exception(\n                f\"Max level {OpenApiParser.PAYLOAD_PROPERTIES_HIERARCHY_MAX_DEPTH} of \"\n                f\"traversing payload properties of `{operation_id}` operation is exceeded.\"\n            )\n\n        result = []\n\n        for property_name, property_schema in schema.get(\"properties\", {}).items():\n            default_value = property_schema.get(\"default\", None)\n\n            property = RestApiPayloadProperty(\n                name=property_name,\n                type=property_schema.get(\"type\", None),\n                is_required=property_name in required_properties,\n                properties=self._get_payload_properties(operation_id, property_schema, required_properties, level + 1),\n                description=property_schema.get(\"description\", None),\n                schema=property_schema,\n                default_value=default_value,\n            )","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/connectors/openapi_plugin/openapi_parser.py#L89-L125","documentation":"`_get_payload_properties` recurses into nested object schemas to build the payload property tree, guarded by `PAYLOAD_PROPERTIES_HIERARCHY_MAX_DEPTH`. Once `level` exceeds that constant, it raises a bare `Exception` naming the `operation_id`. This prevents unbounded recursion on self-referential / deeply-nested schemas.","triggerScenarios":"A request-body schema with nesting deeper than `PAYLOAD_PROPERTIES_HIERARCHY_MAX_DEPTH`, including self-referential schemas (`$ref` to an ancestor) that the resolver expanded inline, producing effectively infinite depth.","commonSituations":"Recursive schemas (tree/graph node types) where `$ref` resolution inlined the cycle; very deeply nested DTOs; an over-large bundled spec; a resolver configuration that expanded `$ref`s instead of keeping them as references.","solutions":["Redesign the schema to use `$ref` for recursion (and ensure the resolver keeps refs) instead of inline nesting.","Flatten or simplify the request body schema for the failing operation.","Reduce the depth of the offending DTO / split it into multiple endpoints.","If you control the parser constant locally, raise `PAYLOAD_PROPERTIES_HIERARCHY_MAX_DEPTH`, but treat that as a workaround — the root cause is schema shape."],"exampleFix":"# before: recursive schema inlined -> infinite depth\nPet:\n  type: object\n  properties:\n    parent: { schema inline of Pet }   # raises 1491\n\n# after: use $ref\nPet:\n  type: object\n  properties:\n    parent:\n      $ref: '#/components/schemas/Pet'","handlingStrategy":"validation","validationCode":"MAX_DEPTH = 10  # mirror PAYLOAD_PROPERTIES_HIERARCHY_MAX_DEPTH\n\ndef schema_depth(schema, seen=None) -> int:\n    seen = seen or set()\n    if not isinstance(schema, dict):\n        return 0\n    props = schema.get(\"properties\", {})\n    # treat $ref as terminal to avoid false positives\n    if schema.get(\"$ref\") or id(schema) in seen:\n        return 0\n    seen = seen | {id(schema)}\n    return 1 + max((schema_depth(p.get(\"schema\", p), seen) for p in props.values()), default=0)\n\ndef too_deep(spec, max_depth=MAX_DEPTH) -> list[str]:\n    bad = []\n    for path, methods in spec.get(\"paths\", {}).items():\n        for method, d in methods.items():\n            rb = (d.get(\"requestBody\") or {}).get(\"content\", {})\n            for mt, meta in rb.items():\n                sch = meta.get(\"schema\", {})\n                if schema_depth(sch) > max_depth:\n                    bad.append(f\"{method} {path} {mt}\")\n    return bad","typeGuard":"def is_self_referential_schema(schema, seen=None) -> bool:\n    seen = seen or set()\n    sid = id(schema)\n    if sid in seen:\n        return True\n    seen = seen | {sid}\n    for p in (schema or {}).get(\"properties\", {}).values():\n        if is_self_referential_schema(p.get(\"schema\", p), seen):\n            return True\n    return False","tryCatchPattern":"try:\n    kernel.add_openapi_plugin(plugin_name=\"x\", openapi_parsed_spec=spec)\nexcept Exception as e:  # bare Exception per source\n    if \"Max level\" in str(e) and \"payload properties\" in str(e):\n        # flatten / use $ref, then retry\n        raise\n    raise","preventionTips":["Use `$ref` for recursive schemas instead of inlining.","Keep the resolver from inlining `$ref`s when recursion exists.","Lint specs for schema depth before loading.","Flatten deep DTOs into separate endpoints."],"tags":["openapi-plugin","parsing","schema-depth","semantic-kernel"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}