microsoft/aspire · error · InvalidOperationException

DockerfileBuildAnnotation should exist after calling…

Error message

DockerfileBuildAnnotation should exist after calling PublishAsDockerFile.

What it means

Internal invariant check inside the publish-configuration callback: after the callback runs, the code expects DockerfileBuildAnnotation (added by PublishAsDockerFile) to exist, but it was not found. Hitting this means the resource publish pipeline did not follow the API contract the extension assumes.

Solutions

  1. Ensure PublishAsDockerFile(...) is called on the resource builder so the DockerfileBuildAnnotation is created.
  2. If managing the Dockerfile annotation manually, use the public PublishAsDockerFile API instead.
  3. Check whether a custom event subscriber removes DockerfileBuildAnnotation before publish callbacks run.

Example fix

// before
var app = builder.AddViteApp("frontend", "./frontend");
app.WithRunScript("build:prod"); // annotation missing
// after
var app = builder.AddViteApp("frontend", "./frontend")
    .PublishAsDockerFile();
app.WithRunScript("build:prod");
Defensive patterns

Strategy: try-catch

Validate before calling

if (!resource.TryGetLastAnnotation<DockerfileBuildAnnotation>(out _))
    resource = resource.PublishAsDockerFile();

Type guard

bool HasDockerfileBuildAnnotation(IResource r) => r.TryGetLastAnnotation<DockerfileBuildAnnotation>(out _);

Try / catch

try { ConfigurePublish(builder); }
catch (InvalidOperationException ex) when (ex.Message.Contains("DockerfileBuildAnnotation"))
{
    builder.PublishAsDockerFile(); // then retry configuration
}

Prevention

When it happens

Trigger: Running this publish callback on a resource where PublishAsDockerFile was not invoked (or its annotation was removed), so TryGetAnnotation<DockerfileBuildAnnotation> fails.

Common situations: Custom publish pipelines bypassing PublishAsDockerFile; manually stripping annotations in an AppHost; calling the API out of order on an unsupported resource type.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs:1896

                                    .CopyFrom("build", "/app/.next/standalone", "./", "node:node")
                                    .CopyFrom("build", "/app/.next/static", "./.next/static", "node:node")
                                    .User("node")
                                    .Entrypoint(["node", "server.js"]);
                                break;
                            }
                        }
                    }
                });

                // JavaScript apps default to build-only publishing unless a standalone runtime is enabled.
                if (resource.TryGetLastAnnotation<DockerfileBuildAnnotation>(out var dockerFileAnnotation))
                {
                    dockerFileAnnotation.HasEntrypoint =
                        resource.TryGetLastAnnotation<JavaScriptPublishModeAnnotation>(out _);
                }
                else
                {
                    throw new InvalidOperationException("DockerfileBuildAnnotation should exist after calling PublishAsDockerFile.");
                }
            })
            .WithAnnotation(new ContainerFilesSourceAnnotation() { SourcePath = "/app/dist" })
            .WithBuildScript("build")
            .WithRunScript(runScriptName);

        if (builder.ExecutionContext.IsPublishMode &&
            builder.TryCreateResourceBuilder<ContainerResource>(resource.Name, out var containerBuilder))
        {
            var validationStepName = $"validate-javascript-dockerfile-run-script-{resource.Name}";

            Task WriteValidatedContainerAsync(ManifestPublishingContext context)
            {
                ValidateExistingDockerfileRunScript(resource, containerBuilder.Resource);
                return context.WriteContainerAsync(containerBuilder.Resource);
            }

            resourceBuilder.WithManifestPublishingCallback(WriteValidatedContainerAsync);

View on GitHub (pinned to 25830f84bd)