.Net
HttpWebRequest
GetResponse
ExceptionHandling
HTTP400

.Net HttpWebRequest.GetResponse raises exception when http status code 400 bad request is returned

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

HttpWebRequest.GetResponse() throws a WebException for HTTP 4xx and 5xx responses by design. That includes 400 Bad Request. The key point is that the response still exists; you just have to read it from the exception instead of expecting GetResponse() to return normally.

Why the Exception Happens

HttpWebRequest treats non-success HTTP status codes as request failures and surfaces them through WebException. So code like this will throw when the server responds with 400:

csharp
var request = (HttpWebRequest)WebRequest.Create("https://example.com/api");
using var response = (HttpWebResponse)request.GetResponse();

This behavior often surprises developers who expect the method to return an object for every HTTP response. But the .NET API deliberately forces error handling through exceptions for these status ranges.

Catch WebException and Read the Response

The normal pattern is to catch WebException, then inspect the attached response.

csharp
1using System;
2using System.IO;
3using System.Net;
4
5try
6{
7    var request = (HttpWebRequest)WebRequest.Create("https://example.com/api");
8    using var response = (HttpWebResponse)request.GetResponse();
9    Console.WriteLine((int)response.StatusCode);
10}
11catch (WebException ex) when (ex.Response is HttpWebResponse response)
12{
13    Console.WriteLine($"HTTP {(int)response.StatusCode} {response.StatusCode}");
14
15    using var stream = response.GetResponseStream();
16    using var reader = new StreamReader(stream!);
17    string body = reader.ReadToEnd();
18    Console.WriteLine(body);
19}

That gives you both the status code and the error payload returned by the server.

The Response Body Often Contains the Real Clue

A 400 Bad Request usually means the client sent something malformed or incomplete. The exception itself only tells you that the request failed. The response body often contains the useful explanation, such as:

  • missing required field
  • invalid JSON syntax
  • bad query parameter format
  • unsupported media type details from the server

That is why reading the response stream is often more important than reading the exception message.

Check Method, Headers, and Body

If you are getting 400, the real bug is usually in the request shape. Common issues include:

  • wrong HTTP method
  • incorrect ContentType
  • malformed body payload
  • missing authentication or custom headers
  • wrong query string encoding

For example, when sending JSON, do not forget the content type and body write:

csharp
1using System.IO;
2using System.Net;
3using System.Text;
4
5var request = (HttpWebRequest)WebRequest.Create("https://example.com/api");
6request.Method = "POST";
7request.ContentType = "application/json";
8
9string json = "{\"name\":\"mark\"}";
10byte[] data = Encoding.UTF8.GetBytes(json);
11
12using (var requestStream = request.GetRequestStream())
13{
14    requestStream.Write(data, 0, data.Length);
15}

If the body format does not match what the server expects, 400 is a common result.

HttpWebRequest Is Legacy API

For new code, HttpClient is usually the better choice. It does not force error responses through the same legacy pattern, and it is generally easier to use.

csharp
1using System;
2using System.Net.Http;
3using System.Threading.Tasks;
4
5using var client = new HttpClient();
6var response = await client.GetAsync("https://example.com/api");
7string body = await response.Content.ReadAsStringAsync();
8
9Console.WriteLine((int)response.StatusCode);
10Console.WriteLine(body);

With HttpClient, you decide whether to call EnsureSuccessStatusCode() or handle non-success statuses manually.

Distinguish Transport Failures from HTTP Failures

A 400 is not a network failure. It means the server responded and rejected the request. That is very different from DNS failure, timeout, or connection refusal.

This distinction matters when logging and retrying. Retrying a malformed request usually just repeats the same mistake.

Common Pitfalls

  • Assuming GetResponse() should return normally even for 400 responses.
  • Catching WebException but never reading ex.Response.
  • Looking only at the exception message and ignoring the error body from the server.
  • Retrying a 400 response as if it were a transient network problem.
  • Continuing to use HttpWebRequest in new code when HttpClient would be simpler.

Summary

  • 'HttpWebRequest.GetResponse() throws WebException for HTTP 4xx and 5xx responses by design.'
  • For 400 Bad Request, the response still exists and can be read from ex.Response.
  • The response body often explains what was wrong with the request.
  • Most 400 bugs come from malformed URLs, headers, or body content.
  • In new .NET code, HttpClient is usually the better API.

Course illustration
Course illustration

All Rights Reserved.