{"record":{"id":"f9e937b378389480","repo":"microsoft/aspire","slug":"containerservicemanagedcluster-properties-returned-null","errorCode":null,"errorMessage":"ContainerServiceManagedCluster.Properties returned null.","messagePattern":"ContainerServiceManagedCluster\\.Properties returned null\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Azure.Kubernetes/AksPreviewIngressProfileInjector.cs","lineNumber":167,"sourceCode":"                    /* isRequired */ false,\n                    /* isSecure */ false,\n                    /* defaultValue */ null,\n                    /* format */ null,\n                ])!;\n            enabled.Assign(true);\n        }\n    }\n\n    private static object GetIngressProfileInstance(ContainerServiceManagedCluster aks)\n    {\n        // ContainerServiceManagedCluster.Properties is internal and exposes the\n        // ManagedClusterProperties complex object that owns IngressProfile (also internal).\n        var clusterPropsProp = typeof(ContainerServiceManagedCluster).GetProperty(\n            \"Properties\",\n            BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)\n            ?? throw new InvalidOperationException(\"ContainerServiceManagedCluster.Properties not found via reflection. The Azure.Provisioning surface may have changed; review AksPreviewIngressProfileInjector.\");\n        var clusterProps = clusterPropsProp.GetValue(aks)\n            ?? throw new InvalidOperationException(\"ContainerServiceManagedCluster.Properties returned null.\");\n\n        var ipProp = clusterProps.GetType().GetProperty(\n            \"IngressProfile\",\n            BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)\n            ?? throw new InvalidOperationException(\"ManagedClusterProperties.IngressProfile not found via reflection. The Azure.Provisioning surface may have changed; review AksPreviewIngressProfileInjector.\");\n        var ipInstance = ipProp.GetValue(clusterProps)\n            ?? throw new InvalidOperationException(\"ManagedClusterProperties.IngressProfile was null even after assigning IngressWebAppRouting; the Azure.Provisioning lazy-initialization behavior may have changed.\");\n\n        if (ipInstance.GetType().FullName != IngressProfileTypeFullName)\n        {\n            throw new InvalidOperationException($\"Expected IngressProfile to be a {IngressProfileTypeFullName} but found {ipInstance.GetType().FullName}.\");\n        }\n\n        return ipInstance;\n    }\n}\n","sourceCodeStart":149,"sourceCodeEnd":184,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Azure.Kubernetes/AksPreviewIngressProfileInjector.cs#L149-L184","documentation":"After locating ContainerServiceManagedCluster.Properties via reflection, the injector reads its value; if the reflection GetValue returns null this error is thrown. The injector expects the cluster construct to always carry a non-null internal ManagedClusterProperties instance, so a null indicates the provisioning model's initialization behavior changed.","triggerScenarios":"AksPreviewIngressProfileInjector.Inject runs (gatewayApi or applicationLoadBalancer enabled on an AKS cluster), the Properties property exists via reflection, but the installed Azure.Provisioning.ContainerService version returns null from the Properties getter — e.g. a version where the complex object is only created on first typed-property access rather than in the constructor.","commonSituations":"Package upgrade to a different Azure.Provisioning.ContainerService beta with changed lazy-init semantics; building the cluster via a different construction path that skips Properties initialization; mixing mismatched Azure.Provisioning core and ContainerService assemblies.","solutions":["Pin Azure.Provisioning.ContainerService to 1.0.0-beta.6 (the version this injector was written for) in Directory.Packages.props","If upgrading deliberately, touch any typed property first (e.g. set a cluster property) before calling the injector so the lazy object initializes, or update the injector to construct the properties object itself","Verify no transitive dependency downgrades/overrides the Azure.Provisioning core assembly — check the resolved versions with dotnet list package --include-transitive","Track microsoft/aspire#17060 and Azure/azure-sdk-for-net#59225 for the typed upstream API that removes the reflection workaround"],"exampleFix":"// before\nvar clusterProps = clusterPropsProp.GetValue(aks)\n    ?? throw new InvalidOperationException(\"ContainerServiceManagedCluster.Properties returned null.\");\n// after (tolerate lazily-initialized models)\nvar clusterProps = clusterPropsProp.GetValue(aks);\nif (clusterProps is null)\n{\n    clusterProps = Activator.CreateInstance(clusterPropsProp.PropertyType, aks);\n    clusterPropsProp.SetValue(aks, clusterProps);\n}","handlingStrategy":"try-catch","validationCode":"var propsProp = typeof(ContainerServiceManagedCluster).GetProperty(\"Properties\", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);\nvar propsValue = propsProp?.GetValue(aks);\nif (propsValue is null)\n{\n    throw new InvalidOperationException(\"Cluster Properties object is null; ensure a typed cluster property was set before injecting preview ingress settings.\");\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    AksPreviewIngressProfileInjector.Inject(aks, gatewayApi, applicationLoadBalancer);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Properties returned null\"))\n{\n    // Lazy-init semantics changed: nudge initialization by setting a typed property first.\n    aks.DnsPrefix ??= BicepValue<string>.Create(\"aspire\");\n    AksPreviewIngressProfileInjector.Inject(aks, gatewayApi, applicationLoadBalancer);\n}","preventionTips":["Set at least one typed cluster property (DnsPrefix, AgentPoolProfiles, etc.) before injecting preview ingress settings","Avoid mixing Azure.Provisioning core and ContainerService packages from different release trains","Confirm resolved package versions with dotnet list package --include-transitive after any bump","Prefer setting the empty IngressWebAppRouting (as Inject does) before reading nested properties"],"tags":["reflection","azure","aks","azure-provisioning","null-value"],"backgroundTag":"unexpected-response-shape","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"}