{"record":{"id":"048aa25dc782ad93","repo":"microsoft/semantic-kernel","slug":"max-level-payloadpropertieshierarchymaxdepth-of","errorCode":null,"errorMessage":"Max level {PayloadPropertiesHierarchyMaxDepth} of traversing payload properties of {operationId} operation is exceeded.","messagePattern":"Max level (.+?) of traversing payload properties of (.+?) operation is exceeded\\.","errorType":"exception","errorClass":"KernelException","httpStatus":null,"severity":"error","filePath":"dotnet/src/Functions/Functions.OpenApi/OpenApi/OpenApiDocumentParser.cs","lineNumber":541,"sourceCode":"    }\n\n    /// <summary>\n    /// Returns REST API payload properties.\n    /// </summary>\n    /// <param name=\"operationId\">The operation id.</param>\n    /// <param name=\"schema\">An OpenAPI document schema representing request body properties.</param>\n    /// <param name=\"level\">Current level in OpenAPI schema.</param>\n    /// <returns>The REST API payload properties.</returns>\n    private static List<RestApiPayloadProperty> GetPayloadProperties(string operationId, OpenApiSchema? schema, int level = 0)\n    {\n        if (schema is null)\n        {\n            return [];\n        }\n\n        if (level > PayloadPropertiesHierarchyMaxDepth)\n        {\n            throw new KernelException($\"Max level {PayloadPropertiesHierarchyMaxDepth} of traversing payload properties of {operationId} operation is exceeded.\");\n        }\n\n        var result = new List<RestApiPayloadProperty>();\n\n        foreach (var propertyPair in schema.Properties)\n        {\n            var propertyName = propertyPair.Key;\n\n            var propertySchema = propertyPair.Value;\n\n            var property = new RestApiPayloadProperty(\n                propertyName,\n                propertySchema.Type,\n                schema.Required.Contains(propertyName),\n                GetPayloadProperties(operationId, propertySchema, level + 1),\n                propertySchema.Description,\n                propertySchema.Format,\n                propertySchema.ToJsonSchema(),","sourceCodeStart":523,"sourceCodeEnd":559,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/dotnet/src/Functions/Functions.OpenApi/OpenApi/OpenApiDocumentParser.cs#L523-L559","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before - recursive node, unbounded depth\n//  components:\n//    schemas:\n//      TreeNode:\n//        type: object\n//        properties:\n//          children:\n//            type: array\n//            items: { $ref: '#/components/schemas/TreeNode' }\n// after - break the cycle for the writable payload\n//  TreeNode:\n//    type: object\n//    properties:\n//      name: { type: string }\n//      children:\n//        type: array\n//        items: { $ref: '#/components/schemas/TreeNode' }\n//        readOnly: true   # excluded from request payload traversal","handlingStrategy":"validation","validationCode":"// Estimate nesting depth of a schema (treating $ref cycles as infinite).\nstatic int MaxDepth(OpenApiSchema s, ISet<OpenApiSchema> seen = null, int depth = 0)\n{\n    seen ??= new HashSet<OpenApiSchema>();\n    if (s is null || !seen.Add(s)) return depth;        // cycle -> stop\n    int best = depth;\n    foreach (var child in s.Properties.Values)\n        best = Math.Max(best, MaxDepth(child, seen, depth + 1));\n    seen.Remove(s);\n    return best;\n}\n// if MaxDepth(schema) > 10 for an operation's body, expect the parser to throw.","typeGuard":"static bool IsWithinPayloadDepth(OpenApiSchema bodySchema, int max = 10) =>\n    MaxDepth(bodySchema) <= max;","tryCatchPattern":"try\n{\n    var plugin = await kernel.CreatePluginFromOpenApiAsync(\"api\", specStream);\n}\ncatch (KernelException ex) when (ex.Message.Contains(\"Max level\") && ex.Message.Contains(\"payload properties\"))\n{\n    // flatten or de-cycle the offending schema, or exclude the operationId, then retry\n}","preventionTips":["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."],"tags":["openapi","dotnet","schema-depth","recursion","configuration"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}