Skip to content

Scanning or adding a GitHub owner crashes on a 404/401/rate limit instead of skipping the owner #444

Description

@matt-edmondson

What's wrong

SyncGitHubRepoInfoForOwner (ProjectDirector/ProjectDirector.cs ~L1006, L1010) fetches repos with .Result:

IEnumerable<Repository> remoteRepos = GitHubClient.Repository.GetAllForUser(owner).Result;
...
remoteRepos = remoteRepos.Concat(GitHubClient.Repository.GetAllForOrg(owner).Result);

and guards it with catch (ApiException) { // skip this owner }. But .Result wraps failures in AggregateException, so the ApiException handler never matches and the error escapes.

The step before it, SyncGitHubOwnerInfo (~L990), calls GitHubClient.User.Get(owner).GetAwaiter().GetResult() with no handler at all, so a 404 there also escapes.

Failure scenario

  • "Add New GitHub Owner" with a typo, or
  • "Scan > GitHub Owners" when a saved owner was renamed or deleted, its PAT was revoked, or the API rate limit is used up

→ NotFoundException / AuthorizationException / RateLimitExceededException (wrapped in AggregateException in the repo-listing path) comes out of an ImGui menu/popup callback on the render thread. The scan stops partway, and the app probably goes down with it. The owner has already been added to Options.GitHubOwners. If that was saved, every later owner scan fails the same way, and there is no UI to remove the owner.

Verified with a scratch test that points Octokit's GitHubClient at a local HttpListener returning 404:

  • GetAllForUser("nobody").Result threw System.AggregateException (inner Octokit.NotFoundException), and catch (Octokit.ApiException) did not catch it.
  • User.Get(...).GetAwaiter().GetResult() threw Octokit.NotFoundException.

Suggested fix

  • Replace .Result with .GetAwaiter().GetResult() (or await) so ApiException is thrown unwrapped.
  • Move the User.Get call into the same guarded region, or catch ApiException in SyncGitHubOwnerInfo too. Also catch HttpRequestException so going offline is handled.
  • Log the skipped owner and the reason rather than swallowing it silently.
  • Related: the "Add New GitHub Owner" path calls SyncGitHubOwnerInfo without ApplyCredentials first, so the new owner is queried with whatever credentials the previous scan left on the shared client. This is the same leak GitHub credentials from one owner leak into the scan of the next, misdirecting private-repo lookups #426 fixed for the scan loop.

Acceptance criteria

  • Adding a nonexistent owner, or scanning with one owner returning 404/401/403 or a rate-limit error, logs a message, skips that owner, and carries on with the rest.

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

    readyFully specified; implement as written

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions