{"record":{"id":"e846f921382f6b2a","repo":"microsoft/aspire","slug":"remoteimagename-must-be-set","errorCode":null,"errorMessage":"RemoteImageName must be set.","messagePattern":"RemoteImageName must be set\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting/ApplicationModel/ContainerImagePushOptions.cs","lineNumber":79,"sourceCode":"    /// <remarks>\n    /// <para>\n    /// This method retrieves the registry endpoint asynchronously and combines it with the remote image name and tag.\n    /// If <see cref=\"RemoteImageTag\"/> is <c>null</c> or empty, \"latest\" is used as the default tag.\n    /// </para>\n    /// <para>\n    /// The <see cref=\"RemoteImageName\"/> value is parsed to determine if it contains an override for the registry\n    /// host or repository. If the <see cref=\"RemoteImageName\"/> contains a host component (detected by the presence\n    /// of a dot in the first segment), that host will be used instead of the registry endpoint. Otherwise, the\n    /// registry endpoint is used and the <see cref=\"IContainerRegistry.Repository\"/> (if set) is prepended to the image name.\n    /// </para>\n    /// </remarks>\n    public async Task<string> GetFullRemoteImageNameAsync(\n        IContainerRegistry registry,\n        CancellationToken cancellationToken = default)\n    {\n        if (string.IsNullOrEmpty(RemoteImageName))\n        {\n            throw new InvalidOperationException(\"RemoteImageName must be set.\");\n        }\n\n        ArgumentNullException.ThrowIfNull(registry);\n\n        var tag = string.IsNullOrEmpty(RemoteImageTag) ? \"latest\" : RemoteImageTag;\n\n        // Parse the RemoteImageName to check if it contains a host override\n        var (host, imagePath) = ParseImageReference(RemoteImageName);\n\n        if (!string.IsNullOrEmpty(host))\n        {\n            // RemoteImageName contains a host, use it directly instead of the registry endpoint\n            return $\"{host}/{imagePath}:{tag}\";\n        }\n\n        // Use the registry endpoint\n        var registryEndpoint = await registry.Endpoint\n            .GetValueAsync(cancellationToken)","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting/ApplicationModel/ContainerImagePushOptions.cs#L61-L97","documentation":"GetFullRemoteImageNameAsync combines the registry, remote image name, and tag into the fully qualified image name used when pushing. The library requires RemoteImageName to be explicitly set because it cannot derive a sane default and pushing without it would produce an invalid repository path. If it is null or empty an InvalidOperationException is thrown before any registry interaction.","triggerScenarios":"Calling GetFullRemoteImageNameAsync on a ContainerImagePushOptions instance whose RemoteImageName property was never assigned (or set to \"\"), e.g. building push options programmatically and forgetting the image name while only setting registry and tag.","commonSituations":"Constructing push options in custom publishing pipelines; migrating code that only set the local image name; building a registry push step dynamically where the image name comes from configuration that returned empty; tests calling the API directly with a partially initialized options object.","solutions":["Set RemoteImageName on the ContainerImagePushOptions before calling GetFullRemoteImageNameAsync.","Validate options in your pipeline before invoking push so empty image names fail fast with a clear message.","If the name comes from configuration, add a startup check that rejects empty values."],"exampleFix":"// before\nvar options = new ContainerImagePushOptions { Registry = registry, RemoteImageTag = \"v1\" };\nvar full = await options.GetFullRemoteImageNameAsync(registry);\n// after\nvar options = new ContainerImagePushOptions { Registry = registry, RemoteImageName = \"myapp/api\", RemoteImageTag = \"v1\" };\nvar full = await options.GetFullRemoteImageNameAsync(registry);","handlingStrategy":"validation","validationCode":"if (options is null) throw new ArgumentNullException(nameof(options));\nif (string.IsNullOrWhiteSpace(options.RemoteImageName))\n    throw new InvalidOperationException(\"RemoteImageName must be set before resolving the full remote image name.\");","typeGuard":null,"tryCatchPattern":"try\n{\n    var full = await options.GetFullRemoteImageNameAsync(registry, ct);\n}\ncatch (InvalidOperationException ex)\n{\n    logger.LogError(ex, \"Push options incomplete: {Message}\", ex.Message);\n    throw new PipelineConfigException(\"Image push options missing RemoteImageName.\", ex);\n}","preventionTips":["Always set RemoteImageName together with Registry when building ContainerImagePushOptions.","Centralize push-option construction in one factory that validates required fields.","Add a startup config check rejecting empty image names.","Unit-test the options factory with a missing-field case."],"tags":["dotnet","aspire","container-image","push"],"backgroundTag":"empty-required-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"}