microsoft/semantic-kernel · error · KernelException
Max level {PayloadPropertiesHierarchyMaxDepth} of traversing
Error message
Max level {PayloadPropertiesHierarchyMaxDepth} of traversing payload properties of {operationId} operation is exceeded. What it means
A safety guard inside GetPayloadProperties: it recursively walks OpenAPI schema Properties and throws KernelException once the recursion 'level' exceeds PayloadPropertiesHierarchyMaxDepth (constant = 10). It exists to bound traversal of deeply-nested or self-referential object schemas so the parser cannot stack-overflow or blow up memory while flattening a request body into RestApiPayloadProperty trees.
Source
Thrown at dotnet/src/Functions/Functions.OpenApi/OpenApi/OpenApiDocumentParser.cs:541
}
/// <summary>
/// Returns REST API payload properties.
/// </summary>
/// <param name="operationId">The operation id.</param>
/// <param name="schema">An OpenAPI document schema representing request body properties.</param>
/// <param name="level">Current level in OpenAPI schema.</param>
/// <returns>The REST API payload properties.</returns>
private static List<RestApiPayloadProperty> GetPayloadProperties(string operationId, OpenApiSchema? schema, int level = 0)
{
if (schema is null)
{
return [];
}
if (level > PayloadPropertiesHierarchyMaxDepth)
{
throw new KernelException($"Max level {PayloadPropertiesHierarchyMaxDepth} of traversing payload properties of {operationId} operation is exceeded.");
}
var result = new List<RestApiPayloadProperty>();
foreach (var propertyPair in schema.Properties)
{
var propertyName = propertyPair.Key;
var propertySchema = propertyPair.Value;
var property = new RestApiPayloadProperty(
propertyName,
propertySchema.Type,
schema.Required.Contains(propertyName),
GetPayloadProperties(operationId, propertySchema, level + 1),
propertySchema.Description,
propertySchema.Format,
propertySchema.ToJsonSchema(),View on GitHub (pinned to c028a0c7dc)
Solutions
- Refactor the offending schema to cap nesting (flatten wide DTOs, split into separate operations) so the realistic depth stays under 10.
- Break self-referential cycles by removing the recursive property from the request schema or marking it read-only (readOnly: true) so it is not part of the writable payload.
- Exclude the problematic operation via OpenApiFunctionExecutionParameters.OperationsToExclude if flattening the schema is not an option.
- If the depth is legitimate and you control the parser, patch PayloadPropertiesHierarchyMaxDepth in a local fork (it is a private const = 10).
Example fix
// before - recursive node, unbounded depth
// components:
// schemas:
// TreeNode:
// type: object
// properties:
// children:
// type: array
// items: { $ref: '#/components/schemas/TreeNode' }
// after - break the cycle for the writable payload
// TreeNode:
// type: object
// properties:
// name: { type: string }
// children:
// type: array
// items: { $ref: '#/components/schemas/TreeNode' }
// readOnly: true # excluded from request payload traversal Defensive patterns
Strategy: validation
Validate before calling
// Estimate nesting depth of a schema (treating $ref cycles as infinite).
static int MaxDepth(OpenApiSchema s, ISet<OpenApiSchema> seen = null, int depth = 0)
{
seen ??= new HashSet<OpenApiSchema>();
if (s is null || !seen.Add(s)) return depth; // cycle -> stop
int best = depth;
foreach (var child in s.Properties.Values)
best = Math.Max(best, MaxDepth(child, seen, depth + 1));
seen.Remove(s);
return best;
}
// if MaxDepth(schema) > 10 for an operation's body, expect the parser to throw. Type guard
static bool IsWithinPayloadDepth(OpenApiSchema bodySchema, int max = 10) =>
MaxDepth(bodySchema) <= max; Try / catch
try
{
var plugin = await kernel.CreatePluginFromOpenApiAsync("api", specStream);
}
catch (KernelException ex) when (ex.Message.Contains("Max level") && ex.Message.Contains("payload properties"))
{
// flatten or de-cycle the offending schema, or exclude the operationId, then retry
} Prevention
- Avoid self-referential writable schemas; mark recursive fields readOnly: true.
- Keep request DTOs shallow; split deep hierarchies into separate endpoints.
- Lint specs for unbounded $ref cycles before import.
When it happens
Trigger: Importing an operation whose requestBody schema nests objects more than 10 levels deep, or a schema that is recursive (a property whose $ref points back to an ancestor type, e.g. a Tree/Node with children of the same type), so each recursion increments level until it passes 10.
Common situations: Specs with self-referential models (org charts, comment threads, category trees, AST nodes), deeply nested DTOs generated from database entity graphs, or circular $ref chains that OpenAPI readers expand rather than keep as references.
Related errors
- Neither of the media types of {operationId} is supported.
- The value type '{value.PrimitiveType}' of {entityDescription
- {nameof(executionParameters.OperationSelectionPredicate)} an
- AZURE_OPENAI_ENDPOINT is not set.
- Agent with name {agentId.Type} not found.
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/048aa25dc782ad93.
Report an issue: GitHub.