Skip to main content

GraphQL Error Catalog

The Hub API surfaces errors as standard GraphQL errors (errors[] with message and optional extensions). This page describes the common failure shapes so apps can branch on them reliably.

Error envelope

{
"errors": [
{
"message": "Unauthorized",
"extensions": { "code": "UNAUTHENTICATED", ... }
}
],
"data": null
}

Apps should key off extensions.code (stable) rather than the human-readable message (may change).

Authentication errors

CodeTriggerApp action
UNAUTHENTICATEDMissing/invalid JWT on a protected fieldCall generateToken, then retry
INVALID_JWTMalformed or expired tokenRe-authenticate
INVALID_PUBLIC_KEYgenerateToken called with a bad public keyValidate key format before calling
— (Proof of key ownership failed: … message)generateToken challenge rejected: timestamp outside the ±120s window or signature doesn't recover to the public keySync the client clock; re-sign the challenge with the correct private key

Protected fields include all createUnsigned* mutations, sendRawTransaction, and accountBalance / accountBalanceUpdated.

Node client errors

The Hub API forwards results from the node WebSocket JSON-RPC. Failures surface as:

CodeTrigger
NODE_UNAVAILABLEHub API could not reach the node (reconnecting)
NODE_TIMEOUTNode RPC did not respond in time
NODE_RPC_ERRORNode returned a JSON-RPC error (signature/nonce/balance)
TX_REJECTEDNode rejected the submitted transaction

For TX_REJECTED / NODE_RPC_ERROR, re-fetch the nonce via the node (get_next_nonce) or via a fresh createUnsigned* call before retrying.

Faucet errors

CodeTrigger
FAUCET_DISABLEDfaucet_enabled = false on the Hub
FAUCET_INVALID_ADDRESSBad recipient address
FAUCET_ERRORFaucet signing/submission failed

Faucet abuse (rate limiting) is enforced at the reverse proxy in production and typically returns HTTP 429, not a GraphQL error. See Security.

Input validation errors

CodeTrigger
BAD_USER_INPUTInvalid coordinates, non-positive fare, malformed tx hash
INVALID_MAP_BOUNDSMapBoundsInput min greater than max

Handling pattern (SDK / app)

const result = await sdk.createUnsignedRideRequest({...});
if (result.errors?.length) {
const code = result.errors[0].extensions?.code;
switch (code) {
case 'UNAUTHENTICATED':
case 'INVALID_JWT':
await sdk.ensureAuth();
return retry();
case 'NODE_UNAVAILABLE':
case 'NODE_TIMEOUT':
await wait(500);
return retry();
case 'TX_REJECTED':
case 'NODE_RPC_ERROR':
// nonce may be stale — rebuild and re-sign
return rebuildAndResubmit();
default:
throw result.errors[0];
}
}

Notes

  • Error extensions.code values are stable across releases; message text is not
  • GraphQL returns HTTP 200 for most errors; only transport-level failures use non-200
  • Subscriptions emit errors on the same WebSocket stream — handle them in your subscription client