Skip to content

DNS, TLS or connection failures escape GitHubDeviceFlow, GitHubProvider and AzureDevOpsProvider as raw HttpRequestException, bypassing the documented GitHostingException hierarchy #155

Description

@matt-edmondson

What's wrong

The hosting layer converts API errors into GitHostingException subclasses, but transport failures from HttpClient are never translated:

  • Hosting/GitHubDeviceFlow.cs:209 and :318: the XML docs at :194 and :280 say GitHostingRequestException is thrown when "GitHub … could not be reached". In practice HttpRequestException propagates.
  • Hosting/AzureDevOpsProvider.cs:142, :205, :273: SendAsync is not wrapped.
  • Hosting/GitHubProvider.cs:101, :227, :263: only Octokit's ApiException is caught.

Nothing in GitIntegration/ handles HttpRequestException.

Repro

Inject a Handler whose SendAsync throws new HttpRequestException("No such host is known."):

Call Thrown
GitHubDeviceFlow.RequestDeviceCodeAsync() System.Net.Http.HttpRequestException
new GitHubProvider { Owner = "contoso", … }.GetRepositoriesAsync() System.Net.Http.HttpRequestException
new AzureDevOpsProvider { Owner = "contoso", … }.GetRepositoriesAsync() System.Net.Http.HttpRequestException

Why it matters

A caller that writes catch (GitHostingException), which is what the docs and CLAUDE.md's "the failure surface is the GitHostingException hierarchy" rule tell them to do, crashes when the machine is offline, DNS fails, or a proxy breaks TLS. The same rule is already enforced for JsonException and ArgumentException. #106 (closed) fixed the same class of leak for NotSupportedException.

Suggested fix

  • Wrap each SendAsync and Octokit call. Translate HttpRequestException into GitHostingRequestException(message, inner).
  • Treat a TaskCanceledException / OperationCanceledException whose token is not the caller's (an HttpClient.Timeout) the same way. Let genuine caller cancellation through unchanged.

Acceptance criteria

  • Fake-handler tests for each provider method and each device-flow call assert that GitHostingRequestException is thrown, with the transport exception as InnerException.
  • A test asserts that caller-token cancellation still surfaces as OperationCanceledException.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions