Problem
Publishers crash or silently drop resources when references cross resource boundaries. This affects all compute environment implementations:
- Docker Compose (
DockerComposeInfrastructure)
- Azure Container Apps (
AzureContainerAppsInfrastructure)
- Azure App Service
- Kubernetes
- Any 3rd-party implementation that follows the same
BeforeStart + GetComputeResources + ResourceMapping pattern
The root pattern is broken and needs to change.
Root cause
All publishers follow the same pattern:
- Subscribe to
BeforeStartEvent
- Iterate
GetComputeResources() (which filters out build-only, excluded, cross-environment resources)
- Build a
ResourceMapping dictionary from only those filtered resources
- Resolve environment variables — which can reference ANY resource, including filtered ones
- 💥
KeyNotFoundException when a callback references a resource not in the mapping
GetComputeResources() makes a premature decision about which resources matter. It conflates "should this resource be deployed" with "should this resource exist in the resolution graph." These are different questions.
Affected publishers
| Publisher |
Mapping |
Crash site |
| Docker Compose |
DockerComposeEnvironmentResource.ResourceMapping |
DockerComposeServiceResourceExtensions.ProcessValueAsync:22 |
| Azure Container Apps |
ContainerAppEnvironmentContext._containerApps |
BaseContainerAppContext:227 |
| Azure App Service |
Similar pattern |
Similar crash |
| Kubernetes |
Similar pattern |
Similar crash |
| 3rd-party |
Anyone using GetComputeResources() |
Same |
Scenario 1: Build-only container referenced by another resource
A JavaScript app without a PublishAs* method is build-only. When another resource references it, the publisher crashes.
var frontend = builder.AddViteApp("frontend", "./frontend")
.WithHttpEndpoint(name: "http", targetPort: 3000);
builder.AddContainer("api", "apiimage")
.WithReference(frontend.GetEndpoint("http"));
Result: KeyNotFoundException during publish-compose step.
Scenario 2: Excluded resource referenced by another resource
var excluded = builder.AddContainer("auth", "authimage")
.WithHttpEndpoint(name: "http", targetPort: 8080)
.ExcludeFromManifest();
builder.AddContainer("api", "apiimage")
.WithReference(excluded.GetEndpoint("http"));
Result: KeyNotFoundException — excluded resource not in mapping.
Scenario 3: Cross-environment resource referenced
var compose1 = builder.AddDockerComposeEnvironment("compose1");
var compose2 = builder.AddDockerComposeEnvironment("compose2");
var db = builder.AddContainer("db", "postgres")
.WithHttpEndpoint(name: "http", targetPort: 5432)
.WithComputeEnvironment(compose2);
builder.AddContainer("api", "apiimage")
.WithComputeEnvironment(compose1)
.WithReference(db.GetEndpoint("http"));
Result: KeyNotFoundException — db not in compose1's mapping.
Scenario 4: Build-only container with no consumer (silent omission)
// User forgot .PublishAsStaticWebsite()
builder.AddViteApp("frontend", "./frontend")
.WithExternalHttpEndpoints();
builder.AddContainer("api", "apiimage");
Result: PIPELINE SUCCEEDED ✅ but frontend is silently missing from output. No error.
Proposed fix
Dependent on #11787 — infrastructure processing runs in BeforeStartEvent, which is too early.
We need to change the pattern that all publishers follow:
- Move infrastructure processing from
BeforeStart into pipeline steps — proper ordering, other subscribers can add annotations first
- Build the full resource mapping — ALL resources get registered (endpoints only), not just compute resources. References never crash.
- Separate "resolvable" from "deployable" — all resources are resolvable (in the mapping), only compute resources are deployable (get
DeploymentTargetAnnotation, appear in output)
- Validate the resource graph — after resolution, check for invalid states:
- Build-only resource not consumed and not explicitly excluded → error with actionable message
- Excluded resource referenced by a deployable resource → error with actionable message
- Update all publishers — Docker Compose first, then replicate to ACA, App Service, K8s
- Document the pattern for 3rd-party implementors
Test cases
4 test cases on branch davidfowl/fix-resource-exclusion in DockerComposeResourceExclusionTests.cs:
ReferencedResourceExcludedFromPublish_ShouldNotCrash
ReferencedResourceTargetingDifferentEnvironment_ShouldNotCrash
ReferencedBuildOnlyContainer_ShouldNotCrash
UnreferencedBuildOnlyContainer_ShouldFailWithClearError
Related
Problem
Publishers crash or silently drop resources when references cross resource boundaries. This affects all compute environment implementations:
DockerComposeInfrastructure)AzureContainerAppsInfrastructure)BeforeStart+GetComputeResources+ResourceMappingpatternThe root pattern is broken and needs to change.
Root cause
All publishers follow the same pattern:
BeforeStartEventGetComputeResources()(which filters out build-only, excluded, cross-environment resources)ResourceMappingdictionary from only those filtered resourcesKeyNotFoundExceptionwhen a callback references a resource not in the mappingGetComputeResources()makes a premature decision about which resources matter. It conflates "should this resource be deployed" with "should this resource exist in the resolution graph." These are different questions.Affected publishers
DockerComposeEnvironmentResource.ResourceMappingDockerComposeServiceResourceExtensions.ProcessValueAsync:22ContainerAppEnvironmentContext._containerAppsBaseContainerAppContext:227GetComputeResources()Scenario 1: Build-only container referenced by another resource
A JavaScript app without a
PublishAs*method is build-only. When another resource references it, the publisher crashes.Result:
KeyNotFoundExceptionduringpublish-composestep.Scenario 2: Excluded resource referenced by another resource
Result:
KeyNotFoundException— excluded resource not in mapping.Scenario 3: Cross-environment resource referenced
Result:
KeyNotFoundException—dbnot incompose1's mapping.Scenario 4: Build-only container with no consumer (silent omission)
Result:
PIPELINE SUCCEEDED✅ butfrontendis silently missing from output. No error.Proposed fix
Dependent on #11787 — infrastructure processing runs in
BeforeStartEvent, which is too early.We need to change the pattern that all publishers follow:
BeforeStartinto pipeline steps — proper ordering, other subscribers can add annotations firstDeploymentTargetAnnotation, appear in output)Test cases
4 test cases on branch
davidfowl/fix-resource-exclusioninDockerComposeResourceExclusionTests.cs:ReferencedResourceExcludedFromPublish_ShouldNotCrashReferencedResourceTargetingDifferentEnvironment_ShouldNotCrashReferencedBuildOnlyContainer_ShouldNotCrashUnreferencedBuildOnlyContainer_ShouldFailWithClearErrorRelated
davidfowl/fix-resource-exclusion