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

  1. Call .WithComputeEnvironment(environment) on the resource builder for each flagged resource, passing the target environment resource.
  2. Reduce the model to a single compute environment if one shared target is actually intended.
  3. Inspect environmentNames in the message to confirm which environments exist, then assign each resource explicitly.
  4. 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

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


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)