microsoft/aspire · error · InvalidOperationException

Gateway ' ' must have a GatewayClassName set via…

Error message

Gateway '{gatewayResource.Name}' must have a GatewayClassName set via WithGatewayClass(). The Gateway API requires a gatewayClassName to select the controller implementation.

What it means

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.

Solutions

  1. Call WithGatewayClass("<controller-class>") on the gateway resource, e.g. WithGatewayClass("istio") or the class name of your Gateway controller.
  2. Verify the GatewayClass exists in the target cluster and matches your installed controller.
  3. Re-publish after setting the gateway class.

Example fix

// before
var gateway = env.AddGateway("public-gw").WithHostname("app.example.com");
// after
var gateway = env.AddGateway("public-gw")
    .WithGatewayClass("istio")
    .WithHostname("app.example.com");
Defensive patterns

Strategy: validation

Validate before calling

if (string.IsNullOrEmpty(gateway.GatewayClassName)) throw new InvalidOperationException("Gateway requires WithGatewayClass before publishing.");

Try / catch

try { PublishAsync(); } catch (InvalidOperationException ex) when (ex.Message.Contains("WithGatewayClass")) { /* set the gateway class and re-publish */ }

Prevention

When it happens

Trigger: Adding a gateway resource to a Kubernetes environment and publishing without calling WithGatewayClass on it.

Common situations: 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.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/9e2c61ffc912e121. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Kubernetes/KubernetesEnvironmentResource.cs:1067

            }
        }
        else if (!string.IsNullOrEmpty(DefaultStorageClassName))
        {
            claim.Spec.StorageClassName = DefaultStorageClassName;
        }

        return claim;
    }

    private async Task BuildGatewayObjects(
        KubernetesGatewayResource gatewayResource,
        Dictionary<IResource, KubernetesResource> deploymentTargets,
        ILogger logger,
        CancellationToken cancellationToken)
    {
        if (gatewayResource.GatewayClassName is null)
        {
            throw new InvalidOperationException(
                $"Gateway '{gatewayResource.Name}' must have a GatewayClassName set via WithGatewayClass(). " +
                $"The Gateway API requires a gatewayClassName to select the controller implementation.");
        }

        var gatewayName = gatewayResource.Name.ToKubernetesResourceName();

        // This whole method re-runs when the deployment-target step executes a second time (once for
        // "before-start", once in the publish/deploy DAG). GeneratedGateway is assigned so it replaces
        // itself, but GeneratedHttpRoutes is appended to — without clearing, every route is emitted
        // twice and the chart renders duplicate HTTPRoute objects with identical names.
        gatewayResource.GeneratedHttpRoutes.Clear();

        var gateway = new GatewayV1
        {
            Metadata = { Name = gatewayName }
        };
        var resolvedHostnames = await ResolveHostnamesAsync(
            gatewayResource.Hostnames,

View on GitHub (pinned to 25830f84bd)