microsoft/aspire · error · IllegalStateException
Union value is of type
Error message
Union value is of type {value.getClass().getName()}, not {type.getName()} What it means
During pipeline execution Aspire validates that every compute resource (e.g. containers/projects with deployment targets) is bound to exactly one compute environment when the app model contains more than one. With a single environment it can be inferred implicitly, but with multiple environments the mapping is ambiguous, so ValidateComputeEnvironmentBindings throws this InvalidOperationException naming the unbound resources and the competing environments.
Solutions
- Call .WithComputeEnvironment(environment) on the resource builder for each flagged resource, passing the target environment resource.
- Reduce the model to a single compute environment if one shared target is actually intended.
- Inspect environmentNames in the message to confirm which environments exist, then assign each resource explicitly.
- Run the publish/deploy pipeline after fixes; the validation re-runs on every execution.
Example fix
// before
var redis = builder.AddRedis("cache"); // ambiguous with multiple environments
// after
var redis = builder.AddRedis("cache")
.WithComputeEnvironment(productionEnvironment); Defensive patterns
Strategy: validation
Validate before calling
// C#: pre-check compute environment binding before publish/deploy
var envs = appModel.Resources.OfType<ComputeEnvironmentResource>().ToList();
if (envs.Count > 1)
{
var unbound = appModel.Resources
.Where(r => r.IsContainer() || r is ProjectResource)
.Where(r => r.Annotations.OfType<ComputeEnvironmentAnnotation>().Count() > 1)
.ToList();
if (unbound.Count > 0) throw new InvalidOperationException("Assign each compute resource to one environment via WithComputeEnvironment.");
} Try / catch
try
{
await pipeline.ExecuteAsync(model);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("not assigned to a compute environment"))
{
logger.LogError(ex, "Ambiguous compute environment binding: {Message}", ex.Message);
} Prevention
- Call WithComputeEnvironment explicitly on every compute resource as soon as the model has more than one environment.
- Keep one environment per AppHost unless multi-targeting is deliberate.
- Review resource builder extensions for missing environment bindings after refactors.
When it happens
Trigger: App model contains 2+ compute environments (e.g. AddAzureEnvironment plus another environment resource) and a compute resource builder never calls WithComputeEnvironment, so publishing cannot decide which environment owns the resource.
Common situations: Apps evolved from single-environment to multi-environment setups where older resources never got an explicit binding; copy-pasted resource definitions missing the WithComputeEnvironment call; code-generated models where the environment registration was added later.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- getValue is only available on server-returned…
- Array params contains empty item
- Cannot use null in a reference expression
- Circular dependency detected in pipeline steps
- Duplicate step name
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/a307939629c46f8b.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.CodeGeneration.Java/Resources/Base.java:84
public static AspireUnion fromValue(Object value) {
return of(value);
}
public Object getValue() {
return value;
}
public boolean is(Class<?> type) {
return value != null && type.isInstance(value);
}
public <T> T getValueAs(Class<T> type) {
if (value == null) {
return null;
}
if (!type.isInstance(value)) {
throw new IllegalStateException("Union value is of type " + value.getClass().getName() + ", not " + type.getName());
}
return type.cast(value);
}
@Override
public String toString() {
return "AspireUnion{" + value + "}";
}
}
@FunctionalInterface
interface AspireAction0 {
void invoke();
}
@FunctionalInterface
interface AspireAction1<T1> {
void invoke(T1 arg1);View on GitHub (pinned to 25830f84bd)