Skip to main content

Pagination and Errors

Listing calls and error handling use the same shape across every provider.

Pagination​

PaginationOptions controls one page request:

PropertyDefaultValid range
Page11 or greater
PageSize301 to 100

A value outside the range throws ArgumentOutOfRangeException before the provider is called.

PagedResult<T> carries one page:

PropertyDescription
ItemsThe items on this page.
PageThe page number.
PageSizeThe effective page size.
TotalCountThe total number of items, or null when the provider does not report one.
HasNextPageWhether another page is available.

The provider fetches exactly one page. VcsManager never fetches all pages in the background.

Provider pagination​

ProviderRequestTotalCountHasNextPageNotes
GitHubpage, per_pagenullLink header with rel="next"GitHub does not report a total for these endpoints.
GitLabpage, per_pageX-Total headerX-Next-Page headerArchived filter is passed to GitLab.
Azure DevOps$top, $skip, or continuationnullComputed by requesting one item more than PageSizeOrganization-level listing is limited to one organization.
Giteapage, limitX-Total-Count when suppliedLink header with rel="next"limit is capped at 50.

Iterate over pages​

var pageNumber = PaginationOptions.DefaultPage;

while (true)
{
var page = await provider.ListRepositoriesAsync(
new RepositoryQuery { Owner = "my-org", IncludeArchived = false },
new PaginationOptions { Page = pageNumber, PageSize = 50 });

foreach (var repository in page.Items)
{
Console.WriteLine(repository.FullName);
}

if (!page.HasNextPage)
{
break;
}

pageNumber++;
}

Do not compare Items.Count with PageSize to decide whether another page exists. Providers can return a short page while more results remain. Use HasNextPage.

Errors​

Every provider failure derives from VcsProviderException:

ExceptionMeaningUseful properties
VcsProviderExceptionBase type for provider failures.IsTransient
VcsNotFoundExceptionA resource does not exist.Resource
RepositoryNotFoundExceptionA repository does not exist.Owner, Project, Name
PullRequestNotFoundExceptionA pull request does not exist.Repository, Number
VcsAuthenticationExceptionCredentials are missing or invalid.None
VcsAuthorizationExceptionCredentials are valid but lack permission.None
VcsRateLimitExceptionA provider rate limit is exceeded.RetryAfter
VcsConflictExceptionMerge conflict, changed source commit, or invalid state transition.None
VcsUnsupportedOperationExceptionThe provider or current settings cannot perform the operation.Provider, Operation

General HTTP mapping​

Provider responseCore exception
401 UnauthorizedVcsAuthenticationException
403 ForbiddenVcsAuthorizationException, unless the response is a rate limit
404 Not FoundRepositoryNotFoundException, PullRequestNotFoundException, or VcsNotFoundException
405 Method Not AllowedVcsUnsupportedOperationException for GitHub and GitLab; VcsConflictException for Gitea; otherwise VcsProviderException
409 ConflictVcsConflictException
422 Unprocessable EntityVcsConflictException or VcsProviderException
429 Too Many RequestsVcsRateLimitException
5xx or network failureVcsProviderException with IsTransient = true

Provider nuances​

  • GitHub. Octokit rate-limit exceptions become VcsRateLimitException with RetryAfter from the reset time. Octokit authorization failures become VcsAuthenticationException. A 403 without rate-limit headers becomes VcsAuthorizationException.
  • GitLab. A 403 with a Retry-After header becomes VcsRateLimitException; otherwise it becomes VcsAuthorizationException. HTTP 400 with a duplicate or already-taken message becomes VcsConflictException. Merge conflicts and invalid transitions use VcsConflictException.
  • Azure DevOps. A 400 on merge or completion becomes VcsConflictException. Other 400 responses become VcsProviderException. A 405 is not specially mapped and becomes VcsProviderException. Throttling maps to VcsRateLimitException with RetryAfter when Azure DevOps supplies it.
  • Gitea. A 405 or 423 becomes VcsConflictException, not VcsUnsupportedOperationException. A 403 with a retry delay becomes VcsRateLimitException.

Handle errors​

try
{
await provider.MergePullRequestAsync(
repository,
number,
new MergePullRequestRequest { Method = MergeMethod.Squash });
}
catch (PullRequestNotFoundException)
{
// The pull request was removed or the number is wrong.
}
catch (VcsConflictException exception)
{
// Merge conflict, stale source commit, or invalid transition.
Console.WriteLine(exception.Message);
}
catch (VcsUnsupportedOperationException exception)
{
// The provider or repository settings do not allow this method.
Console.WriteLine($"{exception.Provider}: {exception.Operation}");
}
catch (VcsRateLimitException exception)
{
// Wait for RetryAfter when provided.
await Task.Delay(exception.RetryAfter ?? TimeSpan.FromSeconds(30));
}
catch (VcsAuthenticationException)
{
// Supply a new token.
}
catch (VcsAuthorizationException)
{
// Request more permission.
}
catch (VcsProviderException exception)
{
// Other provider or transport failure.
Console.WriteLine(exception.Message);
}

Retry safety​

OperationAutomatically retried by RetryLayer?
Get repository, list repositories, repository existsYes
Get pull request, list pull requestsYes
Close pull requestYes, because close is idempotent
Create repository, delete repositoryNo
Create pull requestNo
Merge pull requestNo

See Layering for retry options and the retry predicate.

Security​

Error messages include the provider, operation, and a safe resource identifier. They never include tokens, authorization headers, or full request bodies. Provider SDK and raw HTTP exception types never escape a provider package; they are preserved as the inner exception of a core exception.