Error Codes Reference
This page is a comprehensive reference for the error codes returned by the Lumar GraphQL API. Use the extensions.code field in error responses to identify errors programmatically and determine the correct handling strategy.
Error response structure
GraphQL errors appear in the errors array of the response, alongside any partial data that was successfully resolved. Each error object contains:
message— a human-readable description of the errorextensions.code— a machine-readable error code to use for programmatic handlingpath— which part of the query the error relates to
Additional properties may appear in extensions depending on the error type.
{
"data": { "getProject": null },
"errors": [
{
"message": "Entity not found",
"extensions": {
"code": "ENTITY_NOT_FOUND"
},
"path": ["getProject"]
}
]
}
Always inspect both data and errors in every response. GraphQL can return partial data — some fields may resolve successfully while others produce errors. A non-null data object does not mean the request fully succeeded.
Authentication and authorization errors
These errors indicate a problem with the credentials or permissions used to make the request.
| Code | When it occurs | How to handle |
|---|---|---|
UNAUTHENTICATED | No auth token provided, token has expired, or token is invalid | Re-authenticate using createSessionUsingUserKey; redirect to login if in a UI context |
UNAUTHORIZED | The authenticated user does not have the required role or permission for this operation | Check your account role and permissions with your account administrator |
INSUFFICIENT_PERMISSIONS | The user's role does not grant access to the requested resource or operation | Check your role and permissions with your account administrator |
FORBIDDEN | The action is explicitly forbidden for this account or role | Check whether the resource or operation requires elevated permissions |
INCORRECT_USER_KEY_ID_OR_SECRET | The user key ID or secret provided for authentication is incorrect | Verify your key credentials; generate a new user key if needed |
Use UNAUTHENTICATED to trigger a re-authentication flow and UNAUTHORIZED or FORBIDDEN to show a permissions error to the user — these are distinct situations that warrant different responses in your application.
Resource errors
These errors relate to the resources being queried or mutated.
| Code | When it occurs | How to handle |
|---|---|---|
ENTITY_NOT_FOUND | The resource with the given ID does not exist or is not accessible to this account | Verify the ID is correct; check whether the resource has been deleted |
CONFLICT | A duplicate resource would be created (e.g. a project name already taken in this account), or the resource changed while your request was in flight | Re-read the resource and decide from its current state; for a name clash, use a different value |
Validation errors
These errors indicate the request inputs did not pass validation.
| Code | When it occurs | How to handle |
|---|---|---|
BAD_USER_INPUT | Input fails schema validation — wrong type, missing required field, or malformed value | Read the message field for details about which input failed; compare against the schema |
ARGUMENT_VALIDATION_ERROR | A resolver argument failed type-graphql validation rules | Read the message field for specific details about the validation failure |
USER_EMAIL_NOT_BUSINESS_ADDRESS | A signup or email change used a public email provider, a disposable mailbox domain, or (for signup) a + alias | Ask the customer for a business email address; see Business email addresses below |
SEARCH_FILTER_INVALID | A report filter produced an invalid search query — most commonly a malformed regular expression in a filter predicate | Fix the filter (check any regular expressions) before retrying; the same filter will always fail |
NODE_OBJECT_ID_TYPE_UNSUPPORTED | The node query was given an ObjectID whose type it cannot return, because that type is not part of the Entity union | Fetch the object through its own query instead — the type may still be retrievable there. Check you are not passing a related object's ID by mistake (e.g. an API key ID where an account ID is expected); extensions.received names the type you sent |
When you receive BAD_USER_INPUT or ARGUMENT_VALIDATION_ERROR, read the message field carefully. It explains the constraint that was violated and which input is at fault.
Business email addresses
A user must hold a business email address. Addresses whose domain is a public email provider (gmail.com, outlook.com, yahoo.com and thousands of others, including regional and ISP-run webmail) or a disposable, throwaway mailbox service are rejected by:
| Operation | Input | Rejected with |
|---|---|---|
createSelfServeAccount | userEmail — also rejects + in the local part | USER_EMAIL_NOT_BUSINESS_ADDRESS |
createAiVisibilityOnboarding | email — also rejects + in the local part | USER_EMAIL_NOT_BUSINESS_ADDRESS |
addAccountUser | userEmail | ARGUMENT_VALIDATION_ERROR |
updateCurrentUser | email, checked only when its domain differs from the current one | USER_EMAIL_NOT_BUSINESS_ADDRESS |
Treat all four as form-level validation failures and ask the customer for their work address; retrying the same address always fails. The two signup mutations apply the same rule and return the specific USER_EMAIL_NOT_BUSINESS_ADDRESS code, so a client can handle both in one place. createAiVisibilityOnboarding answers an address that has already registered with recoveryRequired: true before applying the rule. addAccountUser is checked by input validation, so it surfaces as ARGUMENT_VALIDATION_ERROR alongside any other constraint on the same input — read the message field to tell which input was at fault.
updateCurrentUser compares domains, not addresses, and only rejects a move onto a new rejected domain. A user whose existing address is on the list can still edit their name, job title, or other profile fields, change the local part of their address, or normalize its domain casing — and can always move to a business domain.
The list of rejected domains is refreshed from public provider and disposable-domain catalogues, so it grows over time. Do not mirror it client-side: an address your own check accepts may still be rejected here, and the authoritative answer is the mutation's response. If a domain belonging to a real organisation is rejected, report it to Lumar support so the classification can be corrected.
Rate limit and quota errors
These errors indicate the request was rejected due to usage limits.
| Code | When it occurs | How to handle |
|---|---|---|
TOO_MANY_REQUESTS | Too many requests have been made within the current time window | Back off and retry using exponential backoff; see Rate Limits |
RATE_LIMIT_EXCEEDED | A single operation's own limit was exceeded, separately from the overall request limit | Wait extensions.retryAfter seconds, which the error carries, before retrying that operation; see Rate Limits |
ACCOUNT_CREDITS_DEPLETED | The account has run out of crawl credits | Upgrade your plan or contact support to increase limits |
Billing errors
These errors indicate the account's billing details need attention before the operation can proceed.
| Code | When it occurs | How to handle |
|---|---|---|
ACCOUNT_SUBSCRIPTION_PAYMENT_METHOD_MISSING | A self-serve subscription cannot be created because the account has no default payment method — most often when reactivating a subscription that was previously cancelled | Send the customer to the billing portal (createBillingPortalSession) to add a payment method or mark a saved one as default, then retry. Retrying without that change always fails |
Pagination errors
| Code | When it occurs | How to handle |
|---|---|---|
EXCESSIVE_PAGINATION | The pagination depth or page size exceeds the allowed limit | Reduce the first or last value; use cursor-based pagination with smaller pages |
Server errors
These errors indicate an unexpected failure on the server side.
| Code | When it occurs | How to handle |
|---|---|---|
SOMETHING_WENT_WRONG | An unexpected server-side error occurred | Retry with exponential backoff; if the error persists, contact support and include the operation name |
Handling multiple errors
A single GraphQL request can return multiple errors — one for each field or input that failed. Inspect the full errors array rather than stopping at the first entry.
if (response.errors?.length) {
const messages = [...new Set(response.errors.map(e => e.message))].join(", ");
const codes = response.errors.map(e => e.extensions?.code);
if (codes.includes("UNAUTHENTICATED")) {
// Redirect to login or trigger token refresh
} else {
// Surface the error message to the user
showError(messages);
}
}
Using a Set when collecting messages deduplicates repeated errors, which is common when the same validation rule fails across multiple fields.
Network errors vs GraphQL errors
Not all failures produce a GraphQL error response. It is important to distinguish between the two:
- Network error — the request failed at the transport level (connection refused, DNS failure, timeout). No response body is available.
- HTTP error — some errors return a non-200 status code (e.g. HTTP 400 for malformed requests, HTTP 401 for invalid credentials). The response body may or may not contain an
errorsarray. Always attempt to parse the response body even for non-200 responses. - GraphQL error — the HTTP response is
200 OKbut theerrorsarray is present. The operation failed at the field level. Thedataobject may still contain partial results for fields that did resolve successfully.
Always check both response.ok (or the HTTP status code) and response.errors in your client code.
Treat a 200 OK response with a non-empty errors array as a partial failure. Do not assume success just because the HTTP status was 200.
Retrying safely
Not all errors are safe to retry. Retrying a request that will always fail wastes quota and delays your application.
| Code | Safe to retry? | Notes |
|---|---|---|
SOMETHING_WENT_WRONG | Yes | Use exponential backoff with a cap |
TOO_MANY_REQUESTS | Yes | Wait for the rate limit window to reset before retrying |
UNAUTHENTICATED | Yes, after token refresh | Refresh or re-obtain the session token first |
ENTITY_NOT_FOUND | No | Fix the resource ID before retrying |
UNAUTHORIZED | No | Check permissions or token validity |
INSUFFICIENT_PERMISSIONS | No | A permissions change is required before retrying |
FORBIDDEN | No | A permissions change is required before retrying |
BAD_USER_INPUT | No | Fix the input validation error before retrying |
ARGUMENT_VALIDATION_ERROR | No | Fix the argument that failed validation before retrying |
USER_EMAIL_NOT_BUSINESS_ADDRESS | No | Use a business email address; the same address always fails |
SEARCH_FILTER_INVALID | No | Fix the invalid filter (e.g. a malformed regular expression) before retrying |
EXCESSIVE_PAGINATION | No | Reduce page size before retrying |
ACCOUNT_CREDITS_DEPLETED | No | A plan upgrade or credit top-up is required |
Blindly retrying non-retryable errors can consume your rate limit budget and result in TOO_MANY_REQUESTS errors on top of the original failure.