Azure / Azure/bicep

Using a for loop with a resource-typed output causes unhandled exception

Open
#9,668 6 comments 0 reactions 0 assignees View on GitHub
bug size: medium story: resource typed params
Dominant language
Bicep
Stars
3.6k
Forks
830
Avg merge
1d 2h
Merged PRs (30d)
79

Description

When compiling with `resourceTypedParamsAndOutputs` enabled, creating an array of resource-typed outputs will trigger an unhandled Newtonsoft exception.

Template:

```bicep
resource sql 'Microsoft.Sql/servers@2021-08-01-preview' existing = [for i in range(0, 10): {
name: 'mysql{i}'
}]

output sql resource = [for i in range(0, 10): sql[i]]
```

Exception encountered:

```
Internal Error - Newtonsoft.Json.JsonSerializationException: Error converting value "Microsoft.Sql/servers@2021-08-01-preview[]" to type 'Azure.Deployments.Core.Entities.TemplateParameterType'. Path '', line 1, position 272.
---> System.ArgumentException: Requested value 'Microsoft.Sql/servers@2021-08-01-preview[]' was not found.
at Newtonsoft.Json.Utilities.EnumUtils.ParseEnum(Type enumType, NamingStrategy namingStrategy, String value, Boolean disallowNumber)
at Newtonsoft.Json.Converters.StringEnumConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
--- End of inner exception stack trace ---
at Newtonsoft.Json.Converters.StringEnumConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
at Newtonsoft.Json.Serialization.JsonSerializerProxy.DeserializeInternal(JsonReader reader, Type objectType)
at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer)
at Azure.Deployments.Core.Json.TemplateGenericPropertyConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Populate(JsonReader reader, Object target)
at Newtonsoft.Json.Serialization.JsonSerializerProxy.PopulateInternal(JsonReader reader, Object target)
at Newtonsoft.Json.JsonSerializer.Populate(JsonReader reader, Object target)
at Azure.Deployments.Core.Json.TemplateObjectConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateDictionary(IDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty containerProperty, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
at Azure.Deployments.Core.Entities.TemplatePropertySerializable.FromJson[T](String jsonString)
at Bicep.Core.Emit.TemplateWriter.GenerateTemplateWithoutHash(PositionTrackingJsonTextWriter jsonWriter) in C:\__w\1\s\bicep\src\Bicep.Core\Emit\TemplateWriter.cs:line 147
at Bicep.Core.Emit.TemplateWriter.Write(SourceAwareJsonTextWriter writer) in C:\__w\1\s\bicep\src\Bicep.Core\Emit\TemplateWriter.cs:line 104
at Bicep.Core.Emit.TemplateEmitter.<>c__DisplayClass8_0.b__0() in C:\__w\1\s\bicep\src\Bicep.Core\Emit\TemplateEmitter.cs:line 68
at Bicep.Core.Emit.TemplateEmitter.EmitOrFail(Func`1 write) in C:\__w\1\s\bicep\src\Bicep.Core\Emit\TemplateEmitter.cs:line 122
at Bicep.Core.Emit.TemplateEmitter.Emit(Stream stream) in C:\__w\1\s\bicep\src\Bicep.Core\Emit\TemplateEmitter.cs:line 59
```

There's no diagnostic message associated with the pattern that causes this exception:
![image](https://user-images.githubusercontent.com/705500/215222641-a88a4750-f866-4561-ae54-c2907fca9d02.png)

Contributor guide

Open the contributing guide

Research direction

Reproduce the supplied template with resourceTypedParamsAndOutputs enabled, then start in src/Bicep.Core/Emit/TemplateWriter.cs at GenerateTemplateWithoutHash and follow the emission path through TemplateEmitter. Done means this resource-typed output array no longer produces an unhandled Newtonsoft.Json exception and instead has the intended compiler behavior, including a diagnostic if the pattern is invalid.

Written by the indexing model from the issue text.

Assessment

Tech stack
json
Domain
compilers
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.