microsoft/semantic-kernel · error · Exception
Max level {OpenApiParser.PAYLOAD_PROPERTIES_HIERARCHY_MAX_DE
Error message
Max level {OpenApiParser.PAYLOAD_PROPERTIES_HIERARCHY_MAX_DEPTH} of traversing payload properties of `{operation_id}` operation is exceeded. What it means
`_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.
Source
Thrown at python/semantic_kernel/connectors/openapi_plugin/openapi_parser.py:107
result.append(
RestApiParameter(
name=name,
type=schema.get("type", "string") if schema else "string",
location=location,
description=description,
is_required=is_required,
default_value=default_value,
schema=schema if schema else {"type": "string"},
)
)
return result
def _get_payload_properties(self, operation_id, schema, required_properties, level=0):
if schema is None:
return []
if level > OpenApiParser.PAYLOAD_PROPERTIES_HIERARCHY_MAX_DEPTH:
raise Exception(
f"Max level {OpenApiParser.PAYLOAD_PROPERTIES_HIERARCHY_MAX_DEPTH} of "
f"traversing payload properties of `{operation_id}` operation is exceeded."
)
result = []
for property_name, property_schema in schema.get("properties", {}).items():
default_value = property_schema.get("default", None)
property = RestApiPayloadProperty(
name=property_name,
type=property_schema.get("type", None),
is_required=property_name in required_properties,
properties=self._get_payload_properties(operation_id, property_schema, required_properties, level + 1),
description=property_schema.get("description", None),
schema=property_schema,
default_value=default_value,
)View on GitHub (pinned to c028a0c7dc)
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.
Example fix
# before: recursive schema inlined -> infinite depth
Pet:
type: object
properties:
parent: { schema inline of Pet } # raises 1491
# after: use $ref
Pet:
type: object
properties:
parent:
$ref: '#/components/schemas/Pet' Defensive patterns
Strategy: validation
Validate before calling
MAX_DEPTH = 10 # mirror PAYLOAD_PROPERTIES_HIERARCHY_MAX_DEPTH
def schema_depth(schema, seen=None) -> int:
seen = seen or set()
if not isinstance(schema, dict):
return 0
props = schema.get("properties", {})
# treat $ref as terminal to avoid false positives
if schema.get("$ref") or id(schema) in seen:
return 0
seen = seen | {id(schema)}
return 1 + max((schema_depth(p.get("schema", p), seen) for p in props.values()), default=0)
def too_deep(spec, max_depth=MAX_DEPTH) -> list[str]:
bad = []
for path, methods in spec.get("paths", {}).items():
for method, d in methods.items():
rb = (d.get("requestBody") or {}).get("content", {})
for mt, meta in rb.items():
sch = meta.get("schema", {})
if schema_depth(sch) > max_depth:
bad.append(f"{method} {path} {mt}")
return bad Type guard
def is_self_referential_schema(schema, seen=None) -> bool:
seen = seen or set()
sid = id(schema)
if sid in seen:
return True
seen = seen | {sid}
for p in (schema or {}).get("properties", {}).values():
if is_self_referential_schema(p.get("schema", p), seen):
return True
return False Try / catch
try:
kernel.add_openapi_plugin(plugin_name="x", openapi_parsed_spec=spec)
except Exception as e: # bare Exception per source
if "Max level" in str(e) and "payload properties" in str(e):
# flatten / use $ref, then retry
raise
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Error parsing OpenAPI document: {openapi_document_path}
- Neither of the media types of {operation_id} is supported.
- This `RestApiParameter` instance is frozen and cannot be mod
- This `RestApiPayload` instance is frozen and cannot be modif
- This instance is frozen and cannot be modified.
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/55f6399815607de2.
Report an issue: GitHub.