Skip to content

Commit 2802d8a

Browse files
Surface root cause in ErrorMessage for wrapped exceptions (#2352)
* Use innermost exception message for ErrorMessage to surface root cause errors When HttpClient wraps errors (e.g. TLS/SSL failures), the outer exception message is generic ("An error occurred while sending the request"). Using GetBaseException().Message surfaces the actual root cause, making diagnostics much easier. The full exception chain remains preserved in ErrorException. Fixes #2278 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add tests verifying ErrorMessage surfaces innermost exception message Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 4511fab commit 2802d8a

3 files changed

Lines changed: 45 additions & 2 deletions

File tree

src/RestSharp/Response/RestResponseBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,6 @@ protected RestResponseBase(RestRequest request) {
161161

162162
internal void AddException(Exception exception) {
163163
ErrorException = exception;
164-
ErrorMessage = exception.Message;
164+
ErrorMessage = exception.GetBaseException().Message;
165165
}
166166
}

src/RestSharp/RestClient.Async.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ static RestResponse GetErrorResponse(RestRequest request, Exception exception, C
6565
ResponseStatus = exception is OperationCanceledException
6666
? TimedOut() ? ResponseStatus.TimedOut : ResponseStatus.Aborted
6767
: ResponseStatus.Error,
68-
ErrorMessage = exception.Message,
68+
ErrorMessage = exception.GetBaseException().Message,
6969
ErrorException = exception
7070
};
7171

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System.Security.Authentication;
2+
3+
namespace RestSharp.Tests;
4+
5+
public class ErrorMessageTests {
6+
[Fact]
7+
public async Task ErrorMessage_surfaces_innermost_exception_message() {
8+
const string innerMessage = "The remote certificate is invalid according to the validation procedure.";
9+
10+
var innerException = new AuthenticationException(innerMessage);
11+
var wrappedException = new HttpRequestException("An error occurred while sending the request.", innerException);
12+
13+
var handler = new FakeHandler(wrappedException);
14+
var client = new RestClient(new RestClientOptions("https://dummy.org") { ConfigureMessageHandler = _ => handler });
15+
16+
var response = await client.ExecuteAsync(new RestRequest("/"));
17+
18+
response.ErrorMessage.Should().Be(innerMessage);
19+
response.ErrorException.Should().BeOfType<HttpRequestException>();
20+
response.ErrorException!.InnerException.Should().BeOfType<AuthenticationException>();
21+
response.ResponseStatus.Should().Be(ResponseStatus.Error);
22+
}
23+
24+
[Fact]
25+
public async Task ErrorMessage_uses_direct_message_when_no_inner_exception() {
26+
const string message = "No such host is known.";
27+
28+
var exception = new HttpRequestException(message);
29+
var handler = new FakeHandler(exception);
30+
var client = new RestClient(new RestClientOptions("https://dummy.org") { ConfigureMessageHandler = _ => handler });
31+
32+
var response = await client.ExecuteAsync(new RestRequest("/"));
33+
34+
response.ErrorMessage.Should().Be(message);
35+
response.ErrorException.Should().BeOfType<HttpRequestException>();
36+
response.ErrorException!.InnerException.Should().BeNull();
37+
}
38+
39+
class FakeHandler(Exception exception) : HttpMessageHandler {
40+
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
41+
=> throw exception;
42+
}
43+
}

0 commit comments

Comments
 (0)