---
title: "Errors & exceptions — Git for Laravel | Roundly"
description: "Every exception the package throws, when it is thrown, and how HTTP statuses from the forge map onto them."
url: https://roundly-consulting.com/open-source/docs/git-for-laravel/exceptions
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Git for Laravel](https://roundly-consulting.com/open-source/docs/git-for-laravel.md)

# Errors & exceptions

The package’s own exceptions live in RoundlyConsulting\\Git\\Exceptions; everything else is Laravel’s own:

| Exception | Thrown when |
| --- | --- |
| `InvalidCredentialsException` | A 401 (no credential, or the forge rejected it) — also while minting an installation token or refreshing an OAuth token; an OAuth refresh answered 400 invalid\_grant (refreshTokenRejected() — reconnect required); an unsupported or wrong credential type; a missing app/OAuth config key; a non-numeric app, installation or repository id; an empty installation scope; an installation that can’t mint (404/422); a missing app permission on repository creation. |
| `FeatureNotSupportedException` | You call something the provider doesn’t support — check supports() first. Also a Bitbucket commit query filtered by author(), since() or until(), and activity() or any actions() call on GitLab and Bitbucket. |
| `RateLimitExceededException` | The client-side limiter would have to wait longer than max\_wait; carries retryAfterSeconds() via HasRetryAfter. |
| `BatchRequestException` | throwOnError() on a BatchResult with failed keys; ->errors holds each BatchError. |
| `OutOfScopeException` | An argument could leave its scope — a path with ., .. or empty segments, \\ or a NUL byte (also once percent-decoded), a ? or # in a repository path or a ? in a ref, a pull request number below 1, a webhook id not in the forge’s shape, a workflow that isn’t a numeric id or one .yml / .yaml file name, a workflow run id that isn’t digits, a repository from another provider — and nothing is sent. Thrown by handles, flat driver methods and batch() alike. Also GitHub’s contents() on a directory path (notAFile(), naming the path). Extends InvalidArgumentException. |
| `Illuminate\Http\Client\RequestException` | Every other refusal — 403, 404, 405, 409, 422, 429, 5xx — with the status on $e->response. |
| `InvalidArgumentException` | An input DTO fails validation, a page size is below 1, a batch()->pullRequest() reference isn’t path#number, a webhook URL can’t be derived, webhooks()->register() would point the package route at a hook it can’t verify or finds a hook at the URL with other events, a GitLab comment has no target, GitLab gets a webhook event it has no flag for, a GitLab owner isn’t a numeric namespace id, a workflow dispatch input isn’t a named string, number or boolean, a run query is filtered by an Unknown status or conclusion, a job query asks for allAttempts() and attempt() together or for an attempt below 1, or a workflow run or job payload carries no usable id. |
| `UnexpectedValueException` | branch() got an answer that isn’t exactly that branch’s head — on GitHub anything but refs/heads/<name> pointing at a commit with a 40-character sha; on GitLab and Bitbucket an answer with no commit. |
| `RoundlyConsulting\PackageToolkit\Exceptions\InvalidConfigurationException` | A config value is present but unusable — an integer outside its range, a boolean outside 1/true/on/yes and 0/false/off/no, an unknown timespan, a non-string string setting, a non-string app id. The message names the key; only a key that is not set — absent, null or blank — takes its default. |

## HTTP statuses

- 401 — InvalidCredentialsException: “requires authentication” with no credential, “rejected the credential” when the forge refused it. The forge’s RequestException is getPrevious().
- 403, 404, 405, 409, 422, 429, 5xx — RequestException with the status on $e->response. A private repository is a 404 to a caller without access; a throttled 403 or 429 stays retryable.
- GitHub App mints and OAuth refreshes — a 401 (a revoked or wrong app key, a refused refresh) becomes InvalidCredentialsException, as does a 404 or 422 while minting an installation token, and an OAuth refresh answered 400 invalid\_grant becomes refreshTokenRejected() (any other 400 stays a RequestException); a 403 stays a RequestException so a throttled minute never marks a working connection as broken.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/git-for-laravel.md)
