Is there an existing issue for this?
Describe the bug
When an ACA-bound resource has an EndpointReference (e.g. via WithEnvironment(name, otherResource.GetEndpoint("http"))) pointing to a resource that ACA's own PrepareDeploymentTargetsAsync didn't claim into _containerApps, ACA's bicep-emission processor unconditionally asks ACA's own internal context for that resource's container-app context — and throws because it's not there.
A resource ends up unclaimed for several distinct reasons:
All three paths converge on ContainerAppEnvironmentContext.GetContainerAppContext(IResource) throwing because the lookup key isn't in _containerApps. A single fix in BaseContainerAppContext.ProcessValue would unblock all three.
The relevant code in BaseContainerAppContext.cs:222-237:
if (value is EndpointReference ep)
{
var context = ep.Resource == resource
? this
: _containerAppEnvironmentContext.GetContainerAppContext(ep.Resource);
var mapping = context._endpointMapping[ep.EndpointName];
var url = GetEndpointValue(mapping, EndpointProperty.Url);
return (url, secretType);
}
And the symmetric EndpointReferenceExpression path at lines 275-285:
if (value is EndpointReferenceExpression epExpr)
{
var context = epExpr.Endpoint.Resource == resource
? this
: _containerAppEnvironmentContext.GetContainerAppContext(epExpr.Endpoint.Resource);
var mapping = context._endpointMapping[epExpr.Endpoint.EndpointName];
var val = GetEndpointValue(mapping, epExpr.Property);
return (val, secretType);
}
_containerAppEnvironmentContext.GetContainerAppContext(IResource) (ContainerAppEnvironmentContext.cs:64-72) only knows about resources its own PrepareDeploymentTargetsAsync claimed (i.e. resources whose GetComputeEnvironment() == this ACA env). For any cross-env target, the lookup throws:
public BaseContainerAppContext GetContainerAppContext(IResource resource)
{
if (!_containerApps.TryGetValue(resource, out var context))
{
throw new InvalidOperationException($"Container app context not found for resource {resource.Name}.");
}
return context;
}
The contract IComputeEnvironmentResource.GetEndpointPropertyExpression(EndpointReferenceExpression) was specifically designed for this case — endpoint resolution dispatched through the OWNING env. ACA's processor never consults it for cross-env endpoints; it assumes everything is ACA-local.
Prior art
@eerhardt opened #16208 "Add cross-environment reference support for App Service and Container Apps" which addressed this exact scenario for the first-party App Service ↔ Container Apps direction by adding TryGetContainerAppContext / TryGetAppServiceContext fallthrough paths in both contexts. It was closed without merging on 2026-04-16 and I couldn't find a follow-up PR.
That PR fixed the symptom for one specific Aspire-internal cross-env pairing. This issue requests a more general fix: dispatch through IComputeEnvironmentResource.GetEndpointPropertyExpression(...) so the resolution works for ANY compute-env integration (including third-party ones built on the public IComputeEnvironmentResource contract) rather than enumerating Aspire-internal cross-env pairs in code.
Related: #13927 manifests the same Container app context not found error message but from a different root cause (ExcludeFromManifest-flagged resources referenced via WithReference).
How I encountered this
I'm experimenting with custom deployment integrations and currently working on one for Azure Static Web Apps — PublishAsAzureStaticWebApp(...) on IResourceBuilder<JavaScriptAppResource> that ships Vite apps via @azure/static-web-apps-cli.
The natural user code for wiring CORS on an ACA-bound .NET backend that should accept calls from SWA-hosted frontends is:
var portal = builder.AddViteApp("portal", "...").WithPnpm().PublishAsAzureStaticWebApp();
var api = builder.AddProject<Projects.Api>("api")
.WithComputeEnvironment(aca)
.WithEnvironment("Cors__AllowedOrigins__0", portal.GetEndpoint("http"));
Running aspire deploy against this AppHost fails during ACA's bicep emission:
[ERR] Container app context not found for resource portal.
portal is a top-level Azure Bicep resource (Microsoft.Web/staticSites) with a defaultHostname output, perfectly addressable via cross-module references. ACA's BaseContainerAppContext.ProcessValue never tries — it goes straight to its internal _containerApps dictionary, which only contains ACA-owned resources, and throws when portal isn't there.
PR #16208 added a TryGetContainerAppContext / TryGetAppServiceContext fallthrough path that handled exactly this for the first-party App Service ↔ ACA pairing — fell back to manifest expressions when no local context existed. This issue requests the same fallthrough be generalised so third-party compute-env integrations (e.g. via the public IComputeEnvironmentResource contract) also participate, not just the first-party pair.
Expected Behavior
When BaseContainerAppContext encounters an EndpointReference (or EndpointReferenceExpression) targeting a resource owned by a different compute environment, it should dispatch endpoint resolution through that env's IComputeEnvironmentResource.GetEndpointPropertyExpression(...) instead of looking up its own _containerApps dictionary.
Sketch of the fix in BaseContainerAppContext.ProcessValue (lines 222-237):
if (value is EndpointReference ep)
{
if (ep.Resource != resource)
{
var foreignEnv = ep.Resource.GetComputeEnvironment();
if (foreignEnv is not null && foreignEnv != _containerAppEnvironmentContext.Environment)
{
// Dispatch to the owning env's expression provider.
var expr = foreignEnv.GetEndpointPropertyExpression(
new EndpointReferenceExpression(ep, EndpointProperty.Url));
// ... thread `expr` through AllocateParameter / etc. as a BicepValue<string>
return (..., secretType);
}
}
// existing ACA-local path
...
}
Symmetric change for the EndpointReferenceExpression branch.
This would let any compute-env integration that correctly implements IComputeEnvironmentResource.GetEndpointPropertyExpression participate in cross-env endpoint resolution without users needing custom workarounds. PR #16208 was already 80% of the way there with TryGetContainerAppContext / TryGetAppServiceContext; generalising to the IComputeEnvironmentResource dispatch path makes it work for arbitrary third-party envs too.
Steps To Reproduce
The minimal repro uses only first-party Aspire APIs (no custom integrations needed) and matches the exact scenarios PR #16208 added tests for:
var builder = DistributedApplication.CreateBuilder(args);
var aca = builder.AddAzureContainerAppEnvironment("aca-env");
var appService = builder.AddAzureAppServiceEnvironment("app-service-env");
var web = builder.AddProject<Projects.Web>("web")
.WithComputeEnvironment(appService);
builder.AddProject<Projects.Api>("api")
.WithComputeEnvironment(aca)
.WithEnvironment("WEB_URL", web.GetEndpoint("http")); // cross-env EndpointReference
builder.Build().Run();
aspire deploy (or aspire publish) against this AppHost throws:
[ERR] Container app context not found for resource web.
The same shape with web on ACA and api on App Service produces the symmetric failure during App Service's bicep emission.
PR #16208's test fixtures cover both directions and were passing in that PR's branch — but the PR was closed unmerged, so the bug still ships in 13.3.5.
Exceptions (if any)
[ERR] Container app context not found for resource <web>.
System.InvalidOperationException: Container app context not found for resource <web>.
at Aspire.Hosting.Azure.AppContainers.ContainerAppEnvironmentContext.GetContainerAppContext(IResource resource)
in /_/src/Aspire.Hosting.Azure.AppContainers/ContainerAppEnvironmentContext.cs:line 68
at Aspire.Hosting.Azure.AppContainers.BaseContainerAppContext.ProcessValue(Object value, SecretType secretType, Object parent)
in /_/src/Aspire.Hosting.Azure.AppContainers/BaseContainerAppContext.cs:line 227
...
Aspire doctor output
Aspire Environment Check
========================
.NET SDK
✅ .NET 10.0.300 installed (x64)
Container Runtime
✅ Podman v5.8.2: running (auto-detected (only runtime running)) ← active
Environment
⚠️ HTTPS development certificate is only partially trusted
Set SSL_CERT_DIR in your shell profile: export SSL_CERT_DIR="$SSL_CERT_DIR:/home/kennethhoff/.aspnet/dev-certs/trust"
See: https://aka.ms/aspire-prerequisites#dev-certs
Details: The certificate is in the trusted store, but SSL_CERT_DIR is not configured to include
'/home/kennethhoff/.aspnet/dev-certs/trust'. Some applications may not trust the certificate.
'aspire run' will configure this automatically.
Summary: 2 passed, 1 warnings, 0 failed
(The dev-cert warning is unrelated to this bug — NixOS environment quirk; the certificate is trusted, just at a non-standard path.)
Anything else?
- Aspire version: 13.3.5
- .NET SDK: 10.0.300 x64
- OS: Linux (NixOS dev shell)
Workaround
My integration exposes a GetHostname() extension that returns a BicepOutputReference (pointing at the SWA module's defaultHostname output) instead of an EndpointReference:
public static BicepOutputReference GetHostname<T>(this IResourceBuilder<T> builder)
where T : JavaScriptAppResource
{
var target = builder.Resource.Annotations
.OfType<AzureStaticWebAppDeploymentTargetAnnotation>()
.LastOrDefault()
?? throw new InvalidOperationException(...);
return target.Module.DefaultHostname;
}
User code becomes:
api.WithEnvironment("Cors__AllowedOrigins__0", portal.GetHostname());
BicepOutputReference is handled correctly by BaseContainerAppContext.ProcessValue at line 254 via AllocateParameter, so the cross-module wiring works.
This workaround is fine for hostname-as-BicepOutput cases but it forces every cross-env compute integration to:
- Expose a separate
GetHostname() / GetUrl() / GetPort() / GetX() API for each endpoint property users might reach for, and
- Train users away from the natural
.GetEndpoint("http") shape they'd use for any same-env resource.
The fix above (dispatching through IComputeEnvironmentResource.GetEndpointPropertyExpression) generalises across all compute envs and all endpoint properties without per-integration boilerplate.
Related observation
IComputeEnvironmentResource.GetEndpointPropertyExpression has a sensible default implementation that composes scheme/host/port/url from GetHostAddressExpression. Any compute-env integration that implements GetHostAddressExpression correctly (e.g. returning a BicepOutputReference to the env's per-resource hostname output) gets cross-env endpoint URL resolution "for free" via the interface — ACA's processor just doesn't take the off-ramp.
Is there an existing issue for this?
Describe the bug
When an ACA-bound resource has an
EndpointReference(e.g. viaWithEnvironment(name, otherResource.GetEndpoint("http"))) pointing to a resource that ACA's ownPrepareDeploymentTargetsAsyncdidn't claim into_containerApps, ACA's bicep-emission processor unconditionally asks ACA's own internal context for that resource's container-app context — and throws because it's not there.A resource ends up unclaimed for several distinct reasons:
model.GetComputeResources()becauseIsContainer() && !IsEmulator() && r is not ProjectResource(e.g. anExecutableResourceswapped to a private nestedExecutableContainerResourcewhoseContainerImageAnnotationwas subsequently stripped). This is the case I directly verified while building a downstream SWA integration.WithComputeEnvironment(otherEnv)was called, ACA'sPrepareDeploymentTargetsAsyncskips the resource (if (resourceComputeEnvironment != this) continue;atAzureContainerAppEnvironmentResource.cs:202-205). I did not verify this case directly, but PR Add cross-environment reference support for App Service and Container Apps #16208 was opened specifically to handle App Service ↔ ACA cross-env references and added tests proving it failed before the PR's fix.ExcludeFromManifest. Reported separately as UsingWithReferenceon a resource that depends on another resource annoatedExcludeFromManifestfails #13927 — same error message, same root cause path (IsExcludedFromPublish() → GetComputeResourcesskips → not in_containerApps).All three paths converge on
ContainerAppEnvironmentContext.GetContainerAppContext(IResource)throwing because the lookup key isn't in_containerApps. A single fix inBaseContainerAppContext.ProcessValuewould unblock all three.The relevant code in
BaseContainerAppContext.cs:222-237:And the symmetric
EndpointReferenceExpressionpath at lines 275-285:_containerAppEnvironmentContext.GetContainerAppContext(IResource)(ContainerAppEnvironmentContext.cs:64-72) only knows about resources its ownPrepareDeploymentTargetsAsyncclaimed (i.e. resources whoseGetComputeEnvironment()== this ACA env). For any cross-env target, the lookup throws:The contract
IComputeEnvironmentResource.GetEndpointPropertyExpression(EndpointReferenceExpression)was specifically designed for this case — endpoint resolution dispatched through the OWNING env. ACA's processor never consults it for cross-env endpoints; it assumes everything is ACA-local.Prior art
@eerhardt opened #16208 "Add cross-environment reference support for App Service and Container Apps" which addressed this exact scenario for the first-party App Service ↔ Container Apps direction by adding
TryGetContainerAppContext/TryGetAppServiceContextfallthrough paths in both contexts. It was closed without merging on 2026-04-16 and I couldn't find a follow-up PR.That PR fixed the symptom for one specific Aspire-internal cross-env pairing. This issue requests a more general fix: dispatch through
IComputeEnvironmentResource.GetEndpointPropertyExpression(...)so the resolution works for ANY compute-env integration (including third-party ones built on the publicIComputeEnvironmentResourcecontract) rather than enumerating Aspire-internal cross-env pairs in code.Related: #13927 manifests the same
Container app context not founderror message but from a different root cause (ExcludeFromManifest-flagged resources referenced viaWithReference).How I encountered this
I'm experimenting with custom deployment integrations and currently working on one for Azure Static Web Apps —
PublishAsAzureStaticWebApp(...)onIResourceBuilder<JavaScriptAppResource>that ships Vite apps via@azure/static-web-apps-cli.The natural user code for wiring CORS on an ACA-bound .NET backend that should accept calls from SWA-hosted frontends is:
Running
aspire deployagainst this AppHost fails during ACA's bicep emission:portalis a top-level Azure Bicep resource (Microsoft.Web/staticSites) with adefaultHostnameoutput, perfectly addressable via cross-module references. ACA'sBaseContainerAppContext.ProcessValuenever tries — it goes straight to its internal_containerAppsdictionary, which only contains ACA-owned resources, and throws whenportalisn't there.PR #16208 added a
TryGetContainerAppContext/TryGetAppServiceContextfallthrough path that handled exactly this for the first-party App Service ↔ ACA pairing — fell back to manifest expressions when no local context existed. This issue requests the same fallthrough be generalised so third-party compute-env integrations (e.g. via the publicIComputeEnvironmentResourcecontract) also participate, not just the first-party pair.Expected Behavior
When
BaseContainerAppContextencounters anEndpointReference(orEndpointReferenceExpression) targeting a resource owned by a different compute environment, it should dispatch endpoint resolution through that env'sIComputeEnvironmentResource.GetEndpointPropertyExpression(...)instead of looking up its own_containerAppsdictionary.Sketch of the fix in
BaseContainerAppContext.ProcessValue(lines 222-237):Symmetric change for the
EndpointReferenceExpressionbranch.This would let any compute-env integration that correctly implements
IComputeEnvironmentResource.GetEndpointPropertyExpressionparticipate in cross-env endpoint resolution without users needing custom workarounds. PR #16208 was already 80% of the way there withTryGetContainerAppContext/TryGetAppServiceContext; generalising to theIComputeEnvironmentResourcedispatch path makes it work for arbitrary third-party envs too.Steps To Reproduce
The minimal repro uses only first-party Aspire APIs (no custom integrations needed) and matches the exact scenarios PR #16208 added tests for:
aspire deploy(oraspire publish) against this AppHost throws:The same shape with
webon ACA andapion App Service produces the symmetric failure during App Service's bicep emission.PR #16208's test fixtures cover both directions and were passing in that PR's branch — but the PR was closed unmerged, so the bug still ships in 13.3.5.
Exceptions (if any)
Aspire doctor output
(The dev-cert warning is unrelated to this bug — NixOS environment quirk; the certificate is trusted, just at a non-standard path.)
Anything else?
Workaround
My integration exposes a
GetHostname()extension that returns aBicepOutputReference(pointing at the SWA module'sdefaultHostnameoutput) instead of anEndpointReference:User code becomes:
BicepOutputReferenceis handled correctly byBaseContainerAppContext.ProcessValueat line 254 viaAllocateParameter, so the cross-module wiring works.This workaround is fine for hostname-as-BicepOutput cases but it forces every cross-env compute integration to:
GetHostname()/GetUrl()/GetPort()/GetX()API for each endpoint property users might reach for, and.GetEndpoint("http")shape they'd use for any same-env resource.The fix above (dispatching through
IComputeEnvironmentResource.GetEndpointPropertyExpression) generalises across all compute envs and all endpoint properties without per-integration boilerplate.Related observation
IComputeEnvironmentResource.GetEndpointPropertyExpressionhas a sensible default implementation that composes scheme/host/port/url fromGetHostAddressExpression. Any compute-env integration that implementsGetHostAddressExpressioncorrectly (e.g. returning aBicepOutputReferenceto the env's per-resource hostname output) gets cross-env endpoint URL resolution "for free" via the interface — ACA's processor just doesn't take the off-ramp.