{"record":{"id":"125c0cbc85ae997c","repo":"microsoft/aspire","slug":"a-valuedescription-of-type-valuetype-name-cannot-be-assigned","errorCode":null,"errorMessage":"A {valueDescription} of type {_valueType.Name} cannot be assigned to a BicepValue<{targetType.Name}>.","messagePattern":"A (.+?) of type (.+?) cannot be assigned to a BicepValue<(.+?)>\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Azure.Provisioning/BicepValueProxy.cs","lineNumber":186,"sourceCode":"    private void EnsureLiteralType(Type targetType)\n    {\n        if (_value.Kind != BicepValueKind.Literal && _valueType == typeof(object))\n        {\n            return;\n        }\n\n        if (targetType.IsAssignableFrom(_valueType))\n        {\n            return;\n        }\n\n        var sourceUnderlyingType = Nullable.GetUnderlyingType(_valueType) ?? _valueType;\n        var targetUnderlyingType = Nullable.GetUnderlyingType(targetType) ?? targetType;\n\n        if (sourceUnderlyingType != targetUnderlyingType)\n        {\n            var valueDescription = _value.Kind == BicepValueKind.Literal ? \"literal\" : \"value\";\n            throw new ArgumentException(\n                $\"A {valueDescription} of type {_valueType.Name} cannot be assigned to a BicepValue<{targetType.Name}>.\");\n        }\n    }\n\n    private IBicepValue GetAssignableValue()\n    {\n        // Azure Provisioning copies secure metadata from the source IBicepValue during assignment.\n        // Composing expressions creates a new SDK value that no longer carries that metadata, so\n        // expose the propagated state through an adapter without changing the emitted expression.\n        return IsSecure && !_value.IsSecure\n            ? new SecureBicepValue(_value)\n            : _value;\n    }\n\n    private sealed class SecureBicepValue(IBicepValue inner) : IBicepValue\n    {\n        public BicepValueKind Kind => inner.Kind;\n","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Azure.Provisioning/BicepValueProxy.cs#L168-L204","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Convert the source literal to the target's underlying type before assignment (int.Parse, ToString, explicit cast).","Check the BicepValue<T> generic argument at the target and match the stored literal type exactly.","If the value comes from config, parse it to the correct type at the boundary instead of passing raw strings.","Search the codebase for other assignments of the same property to keep types consistent after refactors."],"exampleFix":"// before\nproxy.AssignTo(bicepValue); // string \"3\" assigned to BicepValue<int>\n\n// after\nproxy.AssignTo(BicepValueFactory.Create(int.Parse(\"3\"))); // matching int literal","handlingStrategy":"validation","validationCode":"// before assigning, check underlying types match\nType Unwrap(Type t) => Nullable.GetUnderlyingType(t) ?? t;\nif (Unwrap(sourceType) != Unwrap(targetType)) { /* convert the literal first */ }","typeGuard":"bool IsAssignableLiteral<T>(object value) => (Nullable.GetUnderlyingType(value.GetType()) ?? value.GetType()) == (Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T));","tryCatchPattern":"try { proxy.AssignTo(bicepValue); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"cannot be assigned to a BicepValue\")) { /* parse/convert the literal to the target type and reassign */ }","preventionTips":["Parse config strings into the exact numeric/bool type of the Bicep property before assigning.","Keep BicepValue<T> generic arguments and literal-producing code in sync during refactors.","Centralize type conversion at the config boundary so raw strings never reach Bicep assignments."],"tags":["azure","bicep","provisioning","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}