{"record":{"id":"80a04ed370c2ba1d","repo":"microsoft/aspire","slug":"aspire-deep-update-recursion-limit-of-32-exceeded","errorCode":null,"errorMessage":"aspire: deep update recursion limit of '32' exceeded","messagePattern":"aspire: deep update recursion limit of '32' exceeded","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.CodeGeneration.Go/Resources/base.go","lineNumber":890,"sourceCode":"\n\t\tvar result T\n\t\tif reflect.TypeOf(result).Kind() == reflect.Ptr {\n\t\t\tresult = reflect.New(reflect.TypeOf(result).Elem()).Interface().(T)\n\t\t}\n\n\t\tif err := json.Unmarshal(bytes, &result); err != nil {\n\t\t\tpanic(fmt.Sprintf(\"aspire: merge error: %v\", err))\n\t\t}\n\t\treturn result\n\tdefault:\n\t\treturn src\n\t}\n}\n\nfunc merge(dst, src map[string]any, depth int) map[string]any {\n\tconst depthLimit = 32\n\tif depth > depthLimit {\n\t\tpanic(\"aspire: deep update recursion limit of '32' exceeded\")\n\t}\n\n\tfor key, srcVal := range src {\n\t\tif dstVal, ok := dst[key]; ok {\n\t\t\tsrcSub, srcOk := toMap(srcVal)\n\t\t\tdstSub, dstOk := toMap(dstVal)\n\n\t\t\tif srcOk && dstOk {\n\t\t\t\tdst[key] = merge(dstSub, srcSub, depth+1)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tdst[key] = srcVal\n\t}\n\treturn dst\n}\n\nfunc toMap(i any) (map[string]any, bool) {","sourceCodeStart":872,"sourceCodeEnd":908,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.CodeGeneration.Go/Resources/base.go#L872-L908","documentation":"The Go code generation base template's merge function performs a recursive deep-merge of nested map[string]any values and enforces a hard recursion depth of 32. When the merged structures nest deeper than 32 levels it panics to prevent unbounded recursion and stack exhaustion. This is an internal invariant guard for malformed or pathologically nested merge inputs.","triggerScenarios":"Calling deepUpdate/merge with two map[string]any values whose nested sub-maps chain more than 32 levels deep (the depth parameter exceeds the depthLimit constant of 32).","commonSituations":"Generated output from deeply nested cloud resource definitions (deeply nested ARM/Bicep JSON) being merged; accidental self-referential or cyclic map construction; many levels of config/environment overrides stacked programmatically into one tree.","solutions":["Reduce the nesting depth of the maps being merged (flatten or restructure the data model).","Check for accidental cyclic or self-nesting map construction feeding deepUpdate.","Pre-merge shallowly: merge leaf sections individually instead of one whole deep tree.","Restructure the generator rather than raising the limit, since depthLimit is a compiled constant."],"exampleFix":"// before: single merge of an arbitrarily deep tree\nresult := deepUpdate(base, userOverrides)\n// after: merge per top-level section to keep depth bounded\nfor section, override := range userOverrides {\n    deepUpdate(base[section].(map[string]any), override.(map[string]any))\n}","handlingStrategy":"validation","validationCode":"func mapDepth(m map[string]any) int {\n    max := 1\n    for _, v := range m {\n        if sub, ok := v.(map[string]any); ok {\n            if d := mapDepth(sub) + 1; d > max {\n                max = d\n            }\n        }\n    }\n    return max\n}\n// call deepUpdate only if mapDepth(dst) < 30 && mapDepth(src) < 30","typeGuard":"func isMergeSafe(dst, src map[string]any) bool {\n    return mapDepth(dst) < 30 && mapDepth(src) < 30\n}","tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        if s, ok := r.(string); ok && strings.Contains(s, \"recursion limit\") {\n            err = fmt.Errorf(\"merge input nested too deeply: %v\", s)\n        } else {\n            panic(r)\n        }\n    }\n}()","preventionTips":["Flatten deeply nested config models before merging.","Avoid building self-referential map structures.","Merge section-by-section rather than whole deep trees.","Log nesting depth in debug mode when constructing generated trees."],"tags":["go","recursion","code-generation"],"backgroundTag":"internal-invariant-violation","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}