{"record":{"id":"9e2c61ffc912e121","repo":"microsoft/aspire","slug":"gateway-gatewayresource-name-must-have-a-gatewayclassname","errorCode":null,"errorMessage":"Gateway '{gatewayResource.Name}' must have a GatewayClassName set via WithGatewayClass(). The Gateway API requires a gatewayClassName to select the controller implementation.","messagePattern":"Gateway '(.+?)' must have a GatewayClassName set via WithGatewayClass\\(\\)\\. The Gateway API requires a gatewayClassName to select the controller implementation\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Kubernetes/KubernetesEnvironmentResource.cs","lineNumber":1067,"sourceCode":"            }\n        }\n        else if (!string.IsNullOrEmpty(DefaultStorageClassName))\n        {\n            claim.Spec.StorageClassName = DefaultStorageClassName;\n        }\n\n        return claim;\n    }\n\n    private async Task BuildGatewayObjects(\n        KubernetesGatewayResource gatewayResource,\n        Dictionary<IResource, KubernetesResource> deploymentTargets,\n        ILogger logger,\n        CancellationToken cancellationToken)\n    {\n        if (gatewayResource.GatewayClassName is null)\n        {\n            throw new InvalidOperationException(\n                $\"Gateway '{gatewayResource.Name}' must have a GatewayClassName set via WithGatewayClass(). \" +\n                $\"The Gateway API requires a gatewayClassName to select the controller implementation.\");\n        }\n\n        var gatewayName = gatewayResource.Name.ToKubernetesResourceName();\n\n        // This whole method re-runs when the deployment-target step executes a second time (once for\n        // \"before-start\", once in the publish/deploy DAG). GeneratedGateway is assigned so it replaces\n        // itself, but GeneratedHttpRoutes is appended to — without clearing, every route is emitted\n        // twice and the chart renders duplicate HTTPRoute objects with identical names.\n        gatewayResource.GeneratedHttpRoutes.Clear();\n\n        var gateway = new GatewayV1\n        {\n            Metadata = { Name = gatewayName }\n        };\n        var resolvedHostnames = await ResolveHostnamesAsync(\n            gatewayResource.Hostnames,","sourceCodeStart":1049,"sourceCodeEnd":1085,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Kubernetes/KubernetesEnvironmentResource.cs#L1049-L1085","documentation":"The Kubernetes Gateway API requires every Gateway manifest to specify a gatewayClassName that selects the implementing controller. When publishing, KubernetesEnvironmentResource validates each gateway resource and throws InvalidOperationException if GatewayClassName was never set via WithGatewayClass.","triggerScenarios":"Adding a gateway resource to a Kubernetes environment and publishing without calling WithGatewayClass on it.","commonSituations":"Forgetting the gateway-class step when first setting up Kubernetes Gateway API ingress; templates/samples predating the WithGatewayClass requirement; a Gateway controller (e.g. Istio, Envoy Gateway) migration where the class name is now mandatory.","solutions":["Call WithGatewayClass(\"<controller-class>\") on the gateway resource, e.g. WithGatewayClass(\"istio\") or the class name of your Gateway controller.","Verify the GatewayClass exists in the target cluster and matches your installed controller.","Re-publish after setting the gateway class."],"exampleFix":"// before\nvar gateway = env.AddGateway(\"public-gw\").WithHostname(\"app.example.com\");\n// after\nvar gateway = env.AddGateway(\"public-gw\")\n    .WithGatewayClass(\"istio\")\n    .WithHostname(\"app.example.com\");","handlingStrategy":"validation","validationCode":"if (string.IsNullOrEmpty(gateway.GatewayClassName)) throw new InvalidOperationException(\"Gateway requires WithGatewayClass before publishing.\");","typeGuard":null,"tryCatchPattern":"try { PublishAsync(); } catch (InvalidOperationException ex) when (ex.Message.Contains(\"WithGatewayClass\")) { /* set the gateway class and re-publish */ }","preventionTips":["Always call WithGatewayClass when creating a gateway","Keep the controller's gateway class name in a shared constant","Validate gateway configuration in CI publish smoke tests"],"tags":["kubernetes","gateway-api","configuration","missing-argument"],"backgroundTag":"missing-required-config-field","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}