Errors

Every failure the SDK reports, from a service call, the map or a plugin, names what went wrong with a code from one set. This guide covers what every SDK error shares: its codes, the ones worth retrying and how to read a refused API key.

How each part delivers its errors is in its own guide. A service call rejects with an SDKError. The map reports a TomTomMapError to its error handlers, and so do plugins such as 3D Landmarks.

Error codes

An SDK error’s code is an SDKErrorCode:

codeWhen
INVALID_REQUESTThe SDK’s request validation failed, a service couldn’t build a request you sent with validateRequest: false, or the API answered 400 or another 4xx not listed below
INSECURE_BASE_URLcommonBaseURL is neither https: nor http: on a loopback address
INVALID_CREDENTIALSThe API answered 401, because the key is missing, invalid or expired
INSUFFICIENT_PERMISSIONSThe API answered 403, because the key is valid but not allowed this request. See A key refused access
NOT_FOUNDThe API answered 404, or geocodeOne or discoverOnePlace found no place
RATE_LIMITEDThe API still answered 429 after the retries
LIVE_SERVICE_NOT_AVAILABLEThe API answered a 5xx
NETWORK_NOT_AVAILABLENo response arrived: offline, DNS, TLS or CORS failure
ABORTEDThe call’s signal was aborted
WEBGL_UNSUPPORTEDThe browser can’t create the WebGL2 context the map draws with
WEBGL_CONTEXT_LOSTThe browser took the map’s WebGL context away, for example after a GPU reset
STYLE_LOAD_FAILEDThe map style failed to load, and not because of an HTTP status above
INTERNALAnything else, such as a response the SDK couldn’t read
  • Branch on code, not on message. The codes are the stable part. sdkErrorCodes, exported from the Core bundle, lists them all, under the names the TomTom Navigation SDK gives the same failures.
  • Every SDK error also carries sdkVersion, the SDK version to quote in a bug report.

Retrying

An SDK error’s canRetry is true when the failure clears on its own, so the same call is likely to succeed later. That covers RATE_LIMITED, LIVE_SERVICE_NOT_AVAILABLE and NETWORK_NOT_AVAILABLE. On any other code, retrying fails the same way.

Note that a service call answered 429 has already been retried for as long as retry allows before it rejects. The map doesn’t retry its tiles, sprites or glyphs.

A key refused access

A 401 and a 403 are two different problems. INVALID_CREDENTIALS means the API doesn’t know the key. INSUFFICIENT_PERMISSIONS means the key is valid but may not make this request. Its apiErrorCode names the cause of the 403:

apiErrorCodeCauseFix
'Forbidden'The API is not enabled for the keyEnable it for the key, or for a Private Preview API, request access
'InvalidReferer'The key’s domain restriction refused the pageAdd the page’s domain to the key, or set a fixed referrer from your proxy

A service call’s SDKServiceError and the map’s TomTomMapError both carry apiErrorCode, whether the refused request was a service call, the map style, a tile or a plugin’s data. Both implement APIErrorDetails, from the Core bundle, so one TypeScript function can read either.

Private Preview APIs

A Private Preview API, such as Calculate Reachable Range or the 3D Landmarks tiles, needs access granted to the key. The Freemium and Pay As You Grow plans don’t include it. When such an API answers 'Forbidden', or a proxy answers a 403 with no body, the error says so in two places:

  • The message ends with the API that needs access, a link to the Private Preview terms and where to request the access.
  • privatePreviewAccess carries the same information as data, a PrivatePreviewAccess of { product, requestAccessURL }, so you can show your own message.

To tell the reader what to do about a refused key, read the same fields on a service call’s error and the map’s:

import { TomTomMap } from '@tomtom-org/maps-sdk/map';
import { calculateReachableRange, SDKServiceError } from '@tomtom-org/maps-sdk/services';
const explainRefusedKey = (error) => {
if (error.privatePreviewAccess) {
const { product, requestAccessURL } = error.privatePreviewAccess;
return `${product} needs access on your API key: ${requestAccessURL}`;
}
if (error.apiErrorCode === 'InvalidReferer') return 'Add this domain to the API key';
if (error.code === 'INSUFFICIENT_PERMISSIONS') return 'Enable this API for the API key';
if (error.code === 'INVALID_CREDENTIALS') return 'Check the API key';
return undefined;
};
const map = new TomTomMap({ mapLibre: { container: 'map' } });
map.addErrorHandler((error) => {
const explanation = explainRefusedKey(error);
if (explanation) showMessage(explanation);
});
try {
await calculateReachableRange({ origin: [4.9041, 52.3676], budget: { type: 'timeMinutes', value: 30 } });
} catch (error) {
if (!(error instanceof SDKServiceError)) throw error;
showMessage(explainRefusedKey(error) ?? error.message);
}