Skip to content

HCR061

Check HTTP response success before reading content.

Why

HttpClient does not throw for unsuccessful HTTP status codes. Reading response content without first checking success can silently treat errors, throttling responses, or upstream failures as valid payloads.

Bad

var response = await client.GetAsync("https://example.com/orders", cancellationToken);
var json = await response.Content.ReadAsStringAsync(cancellationToken);

Better

var response = await client.GetAsync("https://example.com/orders", cancellationToken);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync(cancellationToken);
var response = await client.GetAsync("https://example.com/orders", cancellationToken);
if (!response.IsSuccessStatusCode)
{
    return null;
}

var json = await response.Content.ReadAsStringAsync(cancellationToken);

Current Detection

The implementation reports local HttpResponseMessage variables initialized or assigned from awaited visible HttpClient calls such as GetAsync(...), PostAsync(...), or SendAsync(...), and synchronous HttpClient.Send(...), when the same block reads response.Content through common synchronous or asynchronous content read methods, including ReadAsStream() and System.Net.Http.Json's ReadFromJsonAsync<T>() and ReadFromJsonAsAsyncEnumerable<T>(), before any visible success handling on that response local. Content reads through order-bounded chains of response aliases and content aliases declared or assigned after response acquisition are also tracked; reassigned aliases are ignored. Parentheses, null-forgiving operators, and explicit response or content casts around tracked expressions do not hide the operation.

Success handling is recognized when the response local or a tracked response alias calls the framework HttpResponseMessage.EnsureSuccessStatusCode() method or when IsSuccessStatusCode or StatusCode is read before content is read in the same execution block or a containing block. A success check that exists only in a sibling conditional branch does not suppress a later unconditional content read. A custom extension that reuses the EnsureSuccessStatusCode name does not count as success evidence. The analyzer stops following the original response when the local is reassigned before content is read, and it does not report when the response is returned or otherwise no content read is visible in the same block. Resolved custom HttpClient and response-like types are skipped. Resolved response acquisition and content-read methods must belong to the BCL HTTP APIs or the official System.Net.Http.Json content extensions, so unrelated custom extensions that reuse known method names are also skipped.

The code fix inserts response.EnsureSuccessStatusCode() immediately after a single response-local declaration or a standalone response assignment. This placement covers both straight-line and nested content reads while ensuring failure is observed before any subsequent response processing.

Suppression

Suppress only when unsuccessful status codes are intentionally valid payload carriers and the status is handled outside the visible code path.

References