diff --git a/cs/src/Management/TunnelManagementClient.cs b/cs/src/Management/TunnelManagementClient.cs index 38ce6644..4a6d0a89 100644 --- a/cs/src/Management/TunnelManagementClient.cs +++ b/cs/src/Management/TunnelManagementClient.cs @@ -10,6 +10,7 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Security.Authentication; +using System.Text.Json; #if NET5_0_OR_GREATER using System.Net.Http.Json; @@ -690,12 +691,29 @@ private string UserLimitsPath throw new ArgumentException(errorMessage, hrex); case HttpStatusCode.Unauthorized: - case HttpStatusCode.Forbidden: - // Enterprise Policies - if (response.Headers.Contains("X-Enterprise-Policy-Failure")) - { - var message = response.Content != null ? await response.Content.ReadAsStringAsync() : string.Empty; - errorMessage = message; + case HttpStatusCode.Forbidden: + // Enterprise Policies + if (response.Headers.Contains("X-Enterprise-Policy-Failure")) + { + var options = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true + }; + var message = response.Content != null ? await response.Content.ReadAsStringAsync() : string.Empty; + + ErrorDetails? errorDetails = null; + try + { + errorDetails = JsonSerializer.Deserialize(message, options); + } + catch (JsonException) + { + // If deserialization fails, it means the message is not in JSON format. + // In this case, use the message directly as the error message. + } + + // Use the deserialized error detail if available, otherwise use the raw message. + errorMessage = errorDetails?.Detail ?? message; } var ex = new UnauthorizedAccessException(errorMessage, hrex); @@ -739,10 +757,11 @@ private string UserLimitsPath /// /// Copied from Microsoft.VsSaaS.Common to avoid taking a dependency on that assembly. /// - private class ErrorDetails - { - public string? Message { get; set; } - public string? StackTrace { get; set; } + private class ErrorDetails + { + public string? Message { get; set; } + public string? StackTrace { get; set; } + public string? Detail { get; set; } } ///