microsoft/aspire · error · ArgumentException

A of type cannot be assigned to a BicepValue< >.

Error message

A {valueDescription} of type {_valueType.Name} cannot be assigned to a BicepValue<{targetType.Name}>.

What it means

Before assigning a stored Bicep value to a BicepValue<T>, EnsureLiteralType compares the underlying types (unwrapping Nullable) of the source value and the target. A mismatch — e.g. assigning a string literal to BicepValue<int> — throws ArgumentException describing both the source ('literal' or 'value') and target types. This prevents Bicep output with wrong-typed values.

Solutions

  1. Convert the source literal to the target's underlying type before assignment (int.Parse, ToString, explicit cast).
  2. Check the BicepValue<T> generic argument at the target and match the stored literal type exactly.
  3. If the value comes from config, parse it to the correct type at the boundary instead of passing raw strings.
  4. Search the codebase for other assignments of the same property to keep types consistent after refactors.

Example fix

// before
proxy.AssignTo(bicepValue); // string "3" assigned to BicepValue<int>

// after
proxy.AssignTo(BicepValueFactory.Create(int.Parse("3"))); // matching int literal
Defensive patterns

Strategy: validation

Validate before calling

// before assigning, check underlying types match
Type Unwrap(Type t) => Nullable.GetUnderlyingType(t) ?? t;
if (Unwrap(sourceType) != Unwrap(targetType)) { /* convert the literal first */ }

Type guard

bool IsAssignableLiteral<T>(object value) => (Nullable.GetUnderlyingType(value.GetType()) ?? value.GetType()) == (Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T));

Try / catch

try { proxy.AssignTo(bicepValue); }
catch (ArgumentException ex) when (ex.Message.Contains("cannot be assigned to a BicepValue")) { /* parse/convert the literal to the target type and reassign */ }

Prevention

When it happens

Trigger: Calling AssignTo (or chaining assignments) where the proxy's stored literal type differs from the BicepValue<T> target type: string to BicepValue<int>, int to BicepValue<string>, double to BicepValue<int>, or nullable-vs-non-null mismatches that unwrap to different underlying types.

Common situations: Config values read as strings assigned to numeric Bicep properties; numeric properties defined as int in app code but long/double in Bicep output; optional values (int?) assigned to non-optional proxies after underlying type drift; refactoring property types without updating assignment sites.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting.Azure.Provisioning/BicepValueProxy.cs:186

    private void EnsureLiteralType(Type targetType)
    {
        if (_value.Kind != BicepValueKind.Literal && _valueType == typeof(object))
        {
            return;
        }

        if (targetType.IsAssignableFrom(_valueType))
        {
            return;
        }

        var sourceUnderlyingType = Nullable.GetUnderlyingType(_valueType) ?? _valueType;
        var targetUnderlyingType = Nullable.GetUnderlyingType(targetType) ?? targetType;

        if (sourceUnderlyingType != targetUnderlyingType)
        {
            var valueDescription = _value.Kind == BicepValueKind.Literal ? "literal" : "value";
            throw new ArgumentException(
                $"A {valueDescription} of type {_valueType.Name} cannot be assigned to a BicepValue<{targetType.Name}>.");
        }
    }

    private IBicepValue GetAssignableValue()
    {
        // Azure Provisioning copies secure metadata from the source IBicepValue during assignment.
        // Composing expressions creates a new SDK value that no longer carries that metadata, so
        // expose the propagated state through an adapter without changing the emitted expression.
        return IsSecure && !_value.IsSecure
            ? new SecureBicepValue(_value)
            : _value;
    }

    private sealed class SecureBicepValue(IBicepValue inner) : IBicepValue
    {
        public BicepValueKind Kind => inner.Kind;

View on GitHub (pinned to 25830f84bd)