Error handling
Every failure throws a subclass of Darvis\ApiLinkedin\Exceptions\LinkedInException, and each kind of failure has its own type. React on the type, never on the message text: the messages are English, have changed before, and are free to change between releases.
use Darvis\ApiLinkedin\Exceptions\LinkedInApiException;
use Darvis\ApiLinkedin\Exceptions\LinkedInConnectionExpired;
use Darvis\ApiLinkedin\Exceptions\LinkedInNotConnected;
use Darvis\ApiLinkedin\Exceptions\LinkedInScopeMissing;
use Darvis\ApiLinkedin\Facades\LinkedIn;
try {
LinkedIn::postAsMember($text);
} catch (LinkedInNotConnected) {
// Nobody connected an account yet.
} catch (LinkedInConnectionExpired) {
// Send the user back through the OAuth flow; the only failure they can fix.
} catch (LinkedInScopeMissing $e) {
// $e->scope was never granted. Add the product to the LinkedIn app and reconnect.
// No request was sent, because LinkedIn would only have answered 403.
} catch (LinkedInApiException $e) {
// $e->operation 'token' | 'profile' | 'publish' | 'organizations' | 'image'
// $e->status HTTP status, 0 when LinkedIn could not be reached
// $e->body raw response body; log it, never show it to a visitor
if ($e->isAuthorizationProblem()) { // 401 or 403: scope or permission issue
// ...
}
if ($e->isConnectionProblem()) { // timeout, DNS, refused: no answer at all
// Worth a retry; getPrevious() is Laravel's ConnectionException.
}
}
| Exception | Meaning | What to do |
|---|---|---|
LinkedInNotConnected | No account is connected. Thrown by every facade method that needs the account | Offer the connect route |
LinkedInConnectionExpired | The token expired and cannot be refreshed | Ask the user to connect again |
LinkedInConfigurationException | postAsOrganization() got no URN and linkedin.organization_urn is empty | Pass a URN or set LINKEDIN_ORGANIZATION_URN; a developer error |
LinkedInScopeMissing | The stored scopes show that the token lacks the scope this call needs ($e->scope): w_organization_social for a company page author or image owner, r_organization_admin for organizations(). Thrown before any request goes out | Add the product to the LinkedIn app and reconnect |
LinkedInApiException | LinkedIn returned an error (operation, status, body), answered a successful call with a body the package cannot use, or could not be reached at all (status 0, isConnectionProblem()) | Log it; check isAuthorizationProblem() and the API version, retry on isConnectionProblem() |
All of them extend LinkedInException, so a single catch (LinkedInException $e) still catches everything. LinkedInConnectionExpired is the one an end user can act on; everything else is a developer error or an upstream failure, and UIs should keep that distinction.
A timeout or an unreachable LinkedIn is part of the same family since 1.8. The package catches Laravel’s Illuminate\Http\Client\ConnectionException on every call and throws a LinkedInApiException with status 0, an empty body and the original exception as getPrevious(). Its message leaves out the address that failed, because an image upload URL is a signed, single-use secret.
$e->getMessage() and $e->body of a LinkedInApiException hold what LinkedIn answered. That belongs in your log. Show a visitor your own sentence instead, the way the built-in callback does; see When connecting fails.
A refused authorization
A denial on the OAuth callback is not an exception but a query string from LinkedIn. AuthorizationDenial::fromCallback($request) reads it, decodes the HTML entities LinkedIn puts in the description, and tells you whether the member declined or your app lacks a product; see Connecting.
Looking up a message
Troubleshooting lists the literal messages of these exceptions and of the connect flow, each with its cause and its fix.
A 403 from LinkedIn while the scope check passed
LinkedInScopeMissing is only thrown when the package knows the scopes of the token. Two cases still reach LinkedIn and come back as a LinkedInApiException with status 403 (isAuthorizationProblem() is true):
- The connection was stored before version 1.4, so its scopes are unknown (
$account->grantedScopes()isnull). - The token has the scope, but the member does not administer that company page.
Reconnecting fixes the first case. The second needs the member to get a role on that page that may post.