Handle errors and retries
Decide what to do from the error code, and retry only the failures that can succeed later.
Every /v2 error has a JSON body with a code. Branch on code. The text of message is for people and can change.
Choose what to do
| Kind of failure | Codes | What to do |
|---|---|---|
| Your request is wrong | 400 codes, 401, 403, 404, 413, 415 |
Fix the request. Retrying unchanged can't help. |
| The points don't work | point_not_snapped, out_of_coverage, no_route, reference_not_found |
Change the input, or tell the user. |
| Too many requests | rate_limited |
Wait for Retry-After, then retry. |
| Monthly data cap reached | data_cap_exceeded |
Don't retry. Email contact@sieitz.com to raise it. |
| A temporary failure | engine_unavailable, unavailable, engine_timeout |
Retry with backoff, then give up. |
| An unexpected reply | internal_error |
Retry once, then report it. |
| Not offered here | capability_unavailable |
Don't retry. Read capabilities from GET /v2/info. |
Both rate_limited and data_cap_exceeded are 429, so check code before you retry. data_cap_exceeded has no Retry-After, and retrying can't help until the cap is raised or the month ends.
Errors lists every code.
Retry with backoff
Wait longer after each attempt, add some randomness, and stop after a few tries. This example retries only the codes that can succeed later.
const RETRY = new Set(["rate_limited", "engine_unavailable", "unavailable", "engine_timeout"]);
async function callWithRetry(url, init, attempts = 4) {
for (let attempt = 0; ; attempt++) {
const res = await fetch(url, init);
if (res.ok) return res.json();
const error = await res.json();
if (!RETRY.has(error.code) || attempt === attempts - 1) throw error;
const retryAfter = Number(res.headers.get("Retry-After")) || 0;
const backoff = 2 ** attempt + Math.random();
await new Promise((resolve) => setTimeout(resolve, Math.max(retryAfter, backoff) * 1000));
}
}Find the point that failed
point_not_snapped and out_of_coverage include details.point_index, the zero-based position of the point that failed. For a matrix, out_of_coverage counts the sources first and then the destinations: with 3 sources, point_index: 4 is the second destination.
Handle a failure that isn't JSON
Check the status before you rely on the body. A network failure or a proxy between you and the API may not return JSON, so treat a body you can't parse as a temporary failure.