Error Handling¶
The errors package provides typed errors and helper functions for handling GitHub API errors.
APIError Type¶
The APIError type wraps GitHub API errors with additional context:
import "github.com/grokify/gogithub/errors"
type APIError struct {
StatusCode int
Message string
Err error // Original error
}
Checking Error Types¶
Use the helper functions to check for specific error conditions:
_, err := repo.GetRepo(ctx, gh, "owner", "nonexistent-repo")
if err != nil {
switch {
case errors.IsNotFound(err):
fmt.Println("Repository not found")
case errors.IsPermissionDenied(err):
fmt.Println("Access denied")
case errors.IsRateLimited(err):
fmt.Println("Rate limit exceeded, try again later")
default:
fmt.Printf("Error: %v\n", err)
}
}
Helper Functions¶
| Function | Status Codes | Description |
|---|---|---|
IsNotFound(err) |
404 | Resource doesn't exist |
IsPermissionDenied(err) |
401, 403 | Authentication or authorization failed |
IsRateLimited(err) |
403 (with rate limit) | API rate limit exceeded |
IsConflict(err) |
409 | Resource conflict (e.g., branch already exists) |
IsValidation(err) |
422 | Validation error (invalid input) |
IsServerError(err) |
500, 502, 503 | GitHub server error |
IsTokenPolicyError(err) |
403 (token policy) | The organization rejects the type of token used |
Translating Errors¶
The Translate function converts GitHub API errors to APIError:
_, resp, err := gh.Repositories.Get(ctx, "owner", "repo")
if err != nil {
apiErr := errors.Translate(err, resp)
fmt.Printf("Status: %d, Message: %s\n", apiErr.StatusCode, apiErr.Message)
}
Getting Status Code¶
Extract the status code from any error:
Returns 0 if the error is not an APIError.
Getting the GitHub Message¶
Extract the message GitHub returned with an error:
Returns an empty string if the error carries no GitHub message.
Token Policy Errors¶
An organization can reject a type of token, for example by forbidding classic
personal access tokens. Requests for the organization then fail with a 403,
while requests for its private repositories fail with a plain 404.
IsTokenPolicyError identifies the 403, which means the request may succeed
with a different kind of credential:
_, err := client.GetUser(ctx, "someorg")
if errors.IsTokenPolicyError(err) {
// Retry with an OAuth app token; see the auth guide.
}
Like IsRateLimitError, it works on raw errors returned directly from a
clientv1 call. To classify access to a single repository, including this
case, use repo.CheckAccess.
Error Unwrapping¶
All error types support Go 1.13+ error unwrapping:
var apiErr *errors.APIError
if errors.As(err, &apiErr) {
fmt.Printf("Status: %d\n", apiErr.StatusCode)
// Access the original error
originalErr := apiErr.Unwrap()
}
Package-Specific Errors¶
Each package defines its own error types for specific operations:
auth.AuthError¶
username, err := auth.GetAuthenticatedUser(ctx, gh)
if err != nil {
var authErr *auth.AuthError
if errors.As(err, &authErr) {
fmt.Printf("Authentication failed: %s\n", authErr.Message)
}
}
repo.CommitError¶
commit, err := repo.CreateCommit(ctx, gh, owner, repo, branch, msg, files)
if err != nil {
var commitErr *repo.CommitError
if errors.As(err, &commitErr) {
fmt.Printf("Commit to %s/%s failed: %v\n",
commitErr.Owner, commitErr.Repo, commitErr.Err)
}
}
repo.BatchError¶
commit, err := batch.Commit(ctx, message)
if err != nil {
var batchErr *repo.BatchError
if errors.As(err, &batchErr) {
fmt.Printf("Batch operation failed: %s\n", batchErr.Message)
}
}
Best Practices¶
1. Check Specific Errors First¶
if errors.IsNotFound(err) {
// Handle 404 specifically
return createResource()
}
if errors.IsRateLimited(err) {
// Wait and retry
time.Sleep(time.Minute)
return retry()
}
// Handle other errors
return err
2. Use Error Wrapping¶
3. Handle Rate Limits Gracefully¶
for retries := 0; retries < 3; retries++ {
result, err := doOperation()
if err == nil {
return result, nil
}
if errors.IsRateLimited(err) {
time.Sleep(time.Duration(retries+1) * time.Minute)
continue
}
return nil, err
}
API Reference¶
See pkg.go.dev/github.com/grokify/gogithub/errors for complete API documentation.