The SDK throws two unchecked exception types. Both extend RuntimeException, so you do not need to declare them in method signatures, but you should catch them in any production code path that calls the Apple Maps API.
AppleMapsApiException
Import: com.williamcallahan.applemaps.adapters.mapsserver.AppleMapsApiException
Thrown when the Apple Maps Server API returns a non-2xx HTTP status code. This covers all server-side rejections: authentication failures (401), quota exhaustion (429), invalid parameters (400), internal server errors (500), and so on.
public final class AppleMapsApiException extends RuntimeException
Constructor
public AppleMapsApiException(String operation, int statusCode, String responseBody)
| Parameter | Type | Description |
|---|
operation | String | Short name of the API operation that failed (for example, "search"). |
statusCode | int | HTTP status code from the Apple Maps Server API response. |
responseBody | String | Raw response body from the API, or an empty string if not available. |
Accessor methods
| Method | Return type | Description |
|---|
statusCode() | int | Returns the HTTP status code (for example, 429, 401, 400). |
responseBody() | String | Returns the raw API response body. May be empty if the API returned no body. Never null. |
getMessage() | String | Returns a message in the form "Apple Maps API request failed for <operation> (status <code>)". |
Common status codes
| Status | Meaning |
|---|
400 | Bad request — check your request parameters. |
401 | Unauthorized — your token is invalid or expired. |
429 | Too Many Requests — daily quota exceeded. See Quota. |
500 | Internal server error on Apple’s side. |
AppleMapsClientException
Import: com.williamcallahan.applemaps.adapters.mapsserver.AppleMapsClientException
Thrown when the HTTP request itself fails before a response is received — for example, due to a network timeout, DNS failure, connection refused, or I/O error. This is distinct from AppleMapsApiException: no HTTP status code is available because the server never responded successfully.
public final class AppleMapsClientException extends RuntimeException
Constructor
public AppleMapsClientException(String operation, Throwable cause)
| Parameter | Type | Description |
|---|
operation | String | Short name of the operation that failed (for example, "autocomplete"). |
cause | Throwable | The underlying network or I/O exception. Accessible via getCause(). |
Accessor methods
| Method | Return type | Description |
|---|
getMessage() | String | Returns a message in the form "Apple Maps request failed for <operation>". |
getCause() | Throwable | Returns the underlying exception (for example, java.net.http.HttpTimeoutException). |
ErrorResponse
Import: com.williamcallahan.applemaps.domain.model.ErrorResponse
A domain record representing the JSON error payload that the Apple Maps Server API returns with 4xx/5xx responses. The raw body is available via AppleMapsApiException.responseBody(). You can deserialize it into this record if you need structured access to the error details.
public record ErrorResponse(String message, List<String> details)
| Field | Type | Description |
|---|
message | String | Human-readable error message from the Apple Maps API. Never null. |
details | List<String> | Additional error detail strings. May be empty but never null. |
Handling exceptions
Wrap any API call in a try/catch block that handles both exception types:
import com.williamcallahan.applemaps.AppleMaps;
import com.williamcallahan.applemaps.adapters.mapsserver.AppleMapsApiException;
import com.williamcallahan.applemaps.adapters.mapsserver.AppleMapsClientException;
import com.williamcallahan.applemaps.domain.model.PlaceResults;
import com.williamcallahan.applemaps.domain.request.GeocodeInput;
try {
PlaceResults results = api.geocode(
GeocodeInput.builder("880 Harrison St, San Francisco, CA 94107").build()
);
results.results().forEach(place -> System.out.println(place.name()));
} catch (AppleMapsApiException e) {
// HTTP error from Apple Maps Server API
System.err.println("API error: " + e.statusCode() + " — " + e.getMessage());
System.err.println("Response body: " + e.responseBody());
if (e.statusCode() == 429) {
// Daily quota exceeded — back off and retry later or contact Apple
System.err.println("Quota exceeded. See https://maps.developer.apple.com/");
}
} catch (AppleMapsClientException e) {
// Network or I/O failure — no HTTP response was received
System.err.println("Client error: " + e.getMessage());
System.err.println("Caused by: " + e.getCause());
}
When resolveCompletionUrls fails, the SDK unwraps the CompletionException and re-throws the original AppleMapsApiException or AppleMapsClientException, so your catch blocks work the same way for concurrent resolution as for single calls.
Both exception types are unchecked (RuntimeException). If you do not catch them, they will propagate up your call stack and may crash your request thread.