NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages

Every exception lives in RoundlyConsulting\Teams\Exceptions and extends TeamsException, which extends RuntimeException. Catch the base type for any package error, or a specific one for targeted handling:

ExceptionThrown byWhen
InviteExpiredExceptionAcceptInviteActionThe invite’s expires_at has passed.
InviteExhaustedExceptionAcceptInviteActionuses has reached max_uses — including a single-use invite already consumed.
InviteEmailMismatchExceptionAcceptInviteActionAn email-targeted invite gets a different or missing email (compared case-insensitively).
InviteNotFoundExceptionTeams::invites()->accept()No invite matches the code, the invite was revoked, or its team was deleted.
InviteNotFoundExceptionfor($t)->invites()->resend() / revoke()The invite belongs to another team.
JoinRequestNotFoundExceptionfor($t)->joinRequests()->approve() / deny()The request belongs to another team.
JoinRequestNotPendingExceptionfor($t)->joinRequests()->approve() / deny()The request was already approved, denied or expired — including by a concurrent responder.
MemberNotFoundExceptionfor($t)->members()->changeRole()The model is not a member of the team.
TeamsExceptionjoinRequests()->open(), members()->add(), transferOwnershipTo()The base class. Thrown directly for an invite-only team’s join request, a join request from an active member, and a reached seat limit.
use RoundlyConsulting\Teams\Exceptions\InviteEmailMismatchException;
use RoundlyConsulting\Teams\Exceptions\InviteExhaustedException;
use RoundlyConsulting\Teams\Exceptions\InviteExpiredException;
use RoundlyConsulting\Teams\Exceptions\InviteNotFoundException;
use RoundlyConsulting\Teams\Exceptions\TeamsException;

try {
    Teams::invites()->accept($code, $user, email: $user->email);
} catch (InviteExpiredException) {
    // the link has expired
} catch (InviteExhaustedException) {
    // no seats left, or a single-use link already consumed
} catch (InviteEmailMismatchException) {
    // the wrong recipient
} catch (InviteNotFoundException) {
    // an unknown code, a revoked invite or a deleted team
} catch (TeamsException $e) {
    // any other teams error — e.g. a seat limit
}

The invite checks run expired → exhausted → revoked → email mismatch → deleted team, so the first failing condition is the one you catch.

Translated messages

The invite, join-request and membership messages come from the teams:: translation namespace:

KeyDefault message
teams::errors.already_memberThe given model is already a member of team #:team.
teams::errors.invite_expiredThe invite ":code" has expired.
teams::errors.invite_email_mismatchThis invite is addressed to ":email".
teams::errors.invite_exhaustedThe invite ":code" has reached its usage limit.
teams::errors.invite_not_foundNo invite was found for the code ":code".
teams::errors.invite_team_missingThe team of invite #:id no longer exists.
teams::errors.invite_unavailableInvite #:id is no longer available.
teams::errors.invite_not_in_teamInvite #:id does not belong to this team.
teams::errors.join_request_not_pendingJoin request #:id has already been resolved.
teams::errors.join_request_not_in_teamJoin request #:id does not belong to this team.
teams::errors.member_not_foundThe given model is not a member of team #:team.
php artisan vendor:publish --tag="teams-translations"
# edit lang/vendor/teams/en/errors.php, or add other locales

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

By donating, you agree to our donation terms.

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.