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

Failures throw RoundlyConsulting\GooglePlaces\Exceptions\PlacesException, with typed accessors so you can branch on what went wrong:

use RoundlyConsulting\GooglePlaces\Exceptions\PlacesException;
use RoundlyConsulting\GooglePlaces\Facades\GooglePlaces;

try {
    $predictions = GooglePlaces::autocomplete('Coffee');
} catch (PlacesException $e) {
    if ($e->isRateLimited())      { /* back off */ }
    elseif ($e->isDenied())       { /* check key / billing / enabled APIs */ }
    elseif ($e->isInvalidRequest()) { /* fix the request */ }
    elseif ($e->isUnreachable())  { /* timeout, DNS failure, refused connection */ }

    report($e); // $e->googleStatus(), $e->googleReason(), $e->googleErrorMessage()
}

The key stays out of messages

The API key never appears in an exception message, an event or a cache key. Every message is redacted — Google’s error text and a transport failure’s too, which ends in the request URL where the Geocoding API carries its key=. The configured key is masked to its last four characters wherever it appears, and so is the value of any key=, token= or signature= query parameter; a value of eight characters or fewer is starred out completely. $e->response is the raw HTTP response, request URL included — don’t serialize it into reports.

Status checks

The checks normalise the error shapes of all three Google APIs, and isUnreachable() separates a network failure from an answer:

CheckGoogle statuses
isRateLimited()RESOURCE_EXHAUSTED, OVER_QUERY_LIMIT — and always for RateLimitExceededException
isDenied()PERMISSION_DENIED, UNAUTHENTICATED, REQUEST_DENIED, OVER_DAILY_LIMIT — or a key/project googleReason such as API_KEY_INVALID, whatever the status
isInvalidRequest()INVALID_ARGUMENT, INVALID_REQUEST — and not denied
isUnreachable()No Google status — Google could not be reached at all (timeout, DNS failure, refused connection)

Inspecting the failure

catch (PlacesException $e) {
    $e->getCode();              // HTTP status of the failed response (0 for local errors)
    $e->googleStatus();         // e.g. "PERMISSION_DENIED", "OVER_QUERY_LIMIT"
    $e->googleReason();         // e.g. "API_KEY_INVALID" — null for the Geocoding API
    $e->googleErrorMessage();   // Google's own error message, if any
    $e->isUnreachable();        // true for a timeout, DNS failure or refused connection
    $e->response;               // ?Illuminate\Http\Client\Response — raw, request URL included
}

When it is thrown

FactoryThrown when
fromResponse()Google returned a non-success response. Carries the HTTP status, Google status and message.
connectionFailed()Google could not be reached after the configured retries — isUnreachable() is true.
missingApiKey()No API key is configured — thrown before any HTTP request.
tooManyPrimaryTypes()An AutocompleteQuery with more than 5 primary types.
tooManyRegionCodes()An AutocompleteQuery with more than 15 region codes.
invalidRadius()A NearbySearchQuery radius outside 0–50000 m.
sessionFinished()A billing session reused after its details() call.
routeNotFound()distance() hit a destination with no available route.
RateLimitExceededException::for()A rate-limited surface would wait longer than its max_wait.

Timeouts and retries

Every call is bounded by http.timeout and http.connect_timeout. Connection failures (timeouts, DNS) are retried http.retries times with http.retry_delay between attempts; Google business errors are never retried — they surface immediately as a PlacesException. Both timeouts are whole seconds of at least 1: 0 (no timeout) or junk such as five throws InvalidConfigurationException instead of leaving a request unbounded.

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.