Skip to content
NexG ConciergeDevelopers

Errors

How errors are shaped, every code the API sends, and what to do about each.

On this page

The error shape

Errors the API decides on are the same JSON object. error.code is for your program and never changes for a given failure; error.message is for people and may be reworded. When a request field is wrong, error.fields names it.

Response
HTTP/1.1 429 Too Many Requests
Cache-Control: no-store
Retry-After: 4
X-Request-Id: 8c1d2b7e-55f3-4a0b-9e2d-6f4a1c3b8d90

{
  "ok": false,
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Try again later."
  },
  "meta": { "api_version": "v1" }
}

Two answers come from the web server instead and have no JSON body: a 404 for a path that does not exist, and a 405 for a method a path does not take. Check the status before you parse.

JSON errors are never cached, and a 429 carries Retry-After, in seconds. Each also carries an X-Request-Id, unique to that response. NexG logs the id of every server error (5xx), so quote it when you report one.

Error codes

The set is small and closed, so you can handle every code.

CodeMeansWhat to do
invalid_requestThe request was not in a shape NexG understands: conflicting credential headers, an unknown or invalid query parameter, or an id that is not a UUID.Fix the request. Sending it again unchanged gets the same answer.
not_foundSomething does not exist, or is not yours. A refused key (401) and a missing scope (403) also use this code, so nobody can tell which keys exist.Read the status: 401, replace the key; 403, check its scopes; 404, the record is not there.
rate_limitedYour token bucket is empty.Wait the seconds in Retry-After, then retry.
internal_errorNexG could not finish the request.Retry with backoff. On 503, NexG could not check your key or limit right now.
method_not_allowedReserved. The API does not send it today.An unsupported method gets an empty 405 instead; see below.

HTTP statuses

StatusWhenRetry?
200It worked. Check ok anyway.—
400invalid_request.No. Fix the request.
401The key was refused.No. Replace the key.
403The key lacks the scope, or no key was sent where one is needed.No
404not_found: no such record. A path that does not exist is also 404, with a web page instead of JSON.No
405The path exists but not for that method. The body is empty.No
429rate_limited.Yes, after Retry-After
500internal_error. NexG logs the request id.Yes, with backoff
503internal_error: NexG could not check the key or the limit.Yes, with backoff

Handling errors

Retry what can succeed on a second try, and stop on what cannot.

JavaScript
async function nexg(url, attempt = 0) {
  const res = await fetch(url, { headers: { 'X-Api-Key': process.env.NEXG_API_KEY } });
  const body = await res.json().catch(() => null);
  if (body?.ok) return body.data;

  const code = body?.error?.code;
  const requestId = res.headers.get('X-Request-Id');

  if (res.status === 429 && attempt < 3) {
    const wait = Number(res.headers.get('Retry-After') ?? 1);
    await new Promise((resolve) => setTimeout(resolve, wait * 1000));
    return nexg(url, attempt + 1);
  }
  if (res.status >= 500 && attempt < 3) {
    await new Promise((resolve) => setTimeout(resolve, 2 ** attempt * 1000));
    return nexg(url, attempt + 1);
  }
  // 400, 401, 403: retrying the same request will not help.
  throw new Error(`NexG ${res.status} ${code ?? 'no_body'} (request ${requestId})`);
}