{"record":{"id":"65f2280d25ce82c0","repo":"microsoft/aspire","slug":"the-endpoint-endpoint-name-for-container-resource","errorCode":null,"errorMessage":"The endpoint '{endpoint.Name}' for container resource '{modelResourceName}' must specify the TargetPort value","messagePattern":"The endpoint '(.+?)' for container resource '(.+?)' must specify the TargetPort value","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting/Dcp/DcpModelUtilities.cs","lineNumber":39,"sourceCode":"    internal static bool ShouldDeferCreateForExplicitStart(IResource modelResource, bool? start)\n    {\n        // Explicit-start, non-persistent resources use manual snapshots for dashboard visibility.\n        // Do not create corresponding DCP objects until the manual start path flips Spec.Start=true; creation\n        // evaluates callbacks that can prompt for input or depend on start-time state.\n        return start == false &&\n            modelResource.TryGetLastAnnotation<ExplicitStartupAnnotation>(out _) &&\n            modelResource.GetLifetimeType() != Lifetime.Persistent;\n    }\n\n    internal static void ValidateEndpointPorts(IResource modelResource, EndpointAnnotation endpoint)\n    {\n        var modelResourceName = modelResource.Name ?? \"(unknown)\";\n\n        if (modelResource.IsContainer())\n        {\n            if (EndpointAnnotation.NormalizePort(endpoint.TargetPort) is null)\n            {\n                throw new InvalidOperationException($\"The endpoint '{endpoint.Name}' for container resource '{modelResourceName}' must specify the {nameof(EndpointAnnotation.TargetPort)} value\");\n            }\n        }\n        else if (!endpoint.IsProxied && endpoint.Port is int && endpoint.Port != endpoint.TargetPort)\n        {\n            throw new InvalidOperationException($\"The endpoint '{endpoint.Name}' for resource '{modelResourceName}' is not using a proxy, and it has a value of {nameof(EndpointAnnotation.Port)} property that is different from the value of {nameof(EndpointAnnotation.TargetPort)} property. For proxy-less endpoints they must match.\");\n        }\n    }\n\n    /// <summary>\n    /// Examines the Aspire resource annotations and adds equivalent ServiceProducerAnnotations to the corresponding DCP resource.\n    /// </summary>\n    internal static void AddServicesProducedInfo<TDcpResource>(\n        RenderedModelResource<TDcpResource> appResource,\n        IEnumerable<IAppResource> appResources)\n        where TDcpResource : CustomResource, IKubernetesStaticMetadata\n    {\n        var modelResource = appResource.ModelResource;\n        var modelResourceName = modelResource.Name ?? \"(unknown)\";","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting/Dcp/DcpModelUtilities.cs#L21-L57","documentation":"When mapping Aspire model endpoints to DCP service annotations, DcpModelUtilities validates that every endpoint on a container resource has a concrete TargetPort. Containers do not get a dynamically assigned port inside the container, so a container endpoint without TargetPort has nothing to bind to, and Aspire throws InvalidOperationException at validation time.","triggerScenarios":"Calling WithEndpoint/WithHttpEndpoint/WithHttpsEndpoint (or WithEndpoint<T>) on a container resource without supplying targetPort, e.g. builder.AddContainer(\"x\",\"img\").WithHttpEndpoint() with no port argument, then running/publishing the AppHost.","commonSituations":"Copying project-style endpoint code (where targetPort is optional) onto containers; refactoring a project resource into a container and forgetting to add the container-side port; forgetting that for containers the 'port' is the in-container listening port.","solutions":["Pass targetPort to WithEndpoint/WithHttpEndpoint on the container resource.","Remember the distinction: for containers, targetPort = the port the app listens on inside the container.","Set the environment variable (e.g. ASPNETCORE_HTTP_PORTS) in the container to match the targetPort.","Use a typed endpoint helper (WithHttpEndpoint(port: ...)) that forces the port argument."],"exampleFix":"// before\nvar cache = builder.AddContainer(\"cache\", \"redis\", \"latest\")\n    .WithHttpEndpoint();\n// after\nvar cache = builder.AddContainer(\"cache\", \"redis\", \"latest\")\n    .WithHttpEndpoint(port: 6379, targetPort: 6379);","handlingStrategy":"validation","validationCode":"static void EnsureContainerEndpointHasTargetPort(IResource resource, EndpointAnnotation e)\n{\n    if (resource.IsContainer() && EndpointAnnotation.NormalizePort(e.TargetPort) is null)\n        throw new InvalidOperationException($\"Endpoint '{e.Name}' on container '{resource.Name}' needs a TargetPort.\");\n}","typeGuard":"static bool HasTargetPort(EndpointAnnotation e) => EndpointAnnotation.NormalizePort(e.TargetPort) is not null;","tryCatchPattern":"try { await builder.Build().RunAsync(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"must specify the TargetPort\"))\n{\n    // fix the endpoint registration on the named container resource\n}","preventionTips":["Always pass targetPort when adding endpoints to container resources","Set the container's listen-port env var to match targetPort","Treat project endpoints and container endpoints as different rules"],"tags":["containers","endpoints","configuration","validation"],"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-21T04:17:39.646Z"}