LocalExtensibilityOperationResponse with ErrorData does not surface details to stdout
Bicep version Bicep CLI version 0.30.23 (ec3612efc7)
Describe the bug
In a custom extension, returning a LocalExtensibilityOperationResponse with a null Resource and a non-null ErrorData does not properly surface the custom error information to the console when running local-deploy command
To Reproduce Sample CreateOrUpdate method:
public Task<LocalExtensibilityOperationResponse> CreateOrUpdate(ResourceSpecification request, CancellationToken cancellationToken)
{
return Task.Run(async () =>
{
try
{
throw new Exception("This is a test exception");
}
catch (Exception ex)
{
return new LocalExtensibilityOperationResponse(
null,
new ErrorData(new Error("123", "", ex.Message, null, null)));
}
});
}
Console output:
Error: ResourceDeploymentFailure - Encountered internal server error. Diagnostic information: timestamp '20241014T232344Z', subscription id '
', tracking id '18242633-eab6-40a9-9807-5b2d077a565d', request correlation id '36f82ab4-2609-4284-aaeb-cf68dcf6bd13'.
Additional context Callstack with BICEP_TRACING_ENABLED:
TRACE: JobError: operationName=DeploymentExtensibleResourceJob.PerformResourceActionAsync, jobPartition=00000000000000000000000000000000, jobId=DeploymentJob:3A2DMOCKRG:3A2DMAIN:3A2D08584726581929737491-6626EB3283E0E8C3, message=Encountered an unhandled exception of type 'JsonSerializationException'. Failing the deployment operation., exception=Newtonsoft.Json.JsonSerializationException: Required property 'type' not found in JSON. Path '', line 1, position 749. at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EndProcessProperty(Object newObject, JsonReader reader, JsonObjectContract contract, Int32 initialDepth, JsonProperty property, PropertyPresence presence, Boolean setDefaultValue) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor
1 creator, String id) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, String id, Boolean& createdFromNonDefaultCreator) 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.JsonSerializer.Deserialize(JsonReader reader, Type objectType) at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.ReadFromStream(Type type, Stream readStream, Encoding effectiveEncoding, IFormatterLogger formatterLogger) at System.Net.Http.Formatting.JsonMediaTypeFormatter.ReadFromStream(Type type, Stream readStream, Encoding effectiveEncoding, IFormatterLogger formatterLogger) at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.ReadFromStream(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger) at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger) --- End of stack trace from previous location --- at System.Net.Http.HttpContentExtensions.ReadAsAsyncCore[T](HttpContent content, Type type, IFormatterLogger formatterLogger, MediaTypeFormatter formatter, CancellationToken cancellationToken) at Azure.Deployments.Engine.Host.Azure.ExtensibilityV2.Contract.Models.ResponseSchema1.EvaluateAsync(HttpResponseMessage responseMessage, CancellationToken cancellationToken) at Azure.Deployments.Engine.Host.Azure.ExtensibilityV2.Contract.ExtensibilityHostApiClientBase.HandleResponseAsync[T](Func1 requestSender, ResponseSchema1 responseSchema, CancellationToken cancellationToken) at Azure.Deployments.Engine.Host.Azure.Workers.DeploymentExtensibleResourceJob.SaveResourceAsync() at Azure.Deployments.Engine.Host.Azure.Workers.DeploymentExtensibleResourceJob.PerformResourceActionAsync(),
Submitted a PR to fix it. Will publish a new version of the deployments package later to incorporate the fix into Bicep.
Identified error still happening with Bicep CLI version 0.31.34+ec82b47d63
It seems that the GRPC call still returns response code 200 (first line of trace) even when ErrorData is not null
TRACE: file:///C:/Users/drrelyea/.bicep/local/sha256_8a09efc8d2fd33f1673ec2b21295ad622b5bee4eaeaa3ec502b1d256184d8205/extension.bin stdout: Request finished HTTP/2 POST http://localhost/extension.BicepExtension/CreateOrUpdate - 200 - application/grpc 31.8963ms TRACE: JobError: operationName=DeploymentExtensibleResourceJob.PerformResourceActionAsync, jobPartition=00000000000000000000000000000000, jobId=DeploymentJob:3A2DMOCKRG:3A2DMAIN:3A2D08584705131292764183-612DDBBBE16D2D92, message=Encountered an unhandled exception of type 'JsonSerializationException'. Failing the deployment operation., exception=Newtonsoft.Json.JsonSerializationException: Required property 'type' not found in JSON. Path '', line 1, position 749. at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EndProcessProperty(Object newObject, JsonReader reader, JsonObjectContract contract, Int32 initialDepth, JsonProperty property, PropertyPresence presence, Boolean setDefaultValue) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor
1 creator, String id) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, String id, Boolean& createdFromNonDefaultCreator) 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.JsonSerializer.Deserialize(JsonReader reader, Type objectType) at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.ReadFromStream(Type type, Stream readStream, Encoding effectiveEncoding, IFormatterLogger formatterLogger) at System.Net.Http.Formatting.JsonMediaTypeFormatter.ReadFromStream(Type type, Stream readStream, Encoding effectiveEncoding, IFormatterLogger formatterLogger) at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.ReadFromStream(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger) at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger) --- End of stack trace from previous location --- at System.Net.Http.HttpContentExtensions.ReadAsAsyncCore[T](HttpContent content, Type type, IFormatterLogger formatterLogger, MediaTypeFormatter formatter, CancellationToken cancellationToken) at Azure.Deployments.Extensibility.V2.Contract.Models.ResponseSchema1.EvaluateAsync(HttpResponseMessage responseMessage, CancellationToken cancellationToken) at Azure.Deployments.Extensibility.V2.Contract.Client.ExtensibilityHostApiClientBase.HandleResponseAsync[T](Func1 requestSender, ResponseSchema1 responseSchema, CancellationToken cancellationToken) at Azure.Deployments.Engine.Host.Azure.Workers.DeploymentExtensibleResourceJob.SaveResourceAsync() at Azure.Deployments.Engine.Host.Azure.Workers.DeploymentExtensibleResourceJob.PerformResourceActionAsync(),
As of Bicep CLI version 0.31.92+b06509316a this issue is resolved