Public API Errors and Error Codes
Public API errors arrive in the GraphQL errors array. Read extensions.code for the reason, such as Unauthorized or NotEnoughPermissions, and keep traceId.
Last updated on
The Chatfuel Public API reports problems in the standard GraphQL errors array, usually with HTTP status 200. Each error carries a machine-readable code in its extensions, such as Unauthorized, NotEnoughPermissions or a business code like ContactDoesNotExist, plus a traceId that Chatfuel support can use to find the request. Base your error handling on the code, never on the message text.
What an error response looks like
The gateway in front of the Chatfuel services wraps errors coming from a service: the outer error has a generic message, and the original errors are in extensions.errors. A virtual user calling createVirtualUser gets a response like this:
{
"data": null,
"errors": [
{
"message": "Failed to fetch from Subgraph 'useraccounting'.",
"extensions": {
"errors": [
{
"message": "auth error",
"path": ["createVirtualUser"],
"extensions": {
"code": "NotEnoughPermissions",
"service": "useraccounting",
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}
]
}
}
]
}The inner extensions can contain:
code: why the operation failed.service: the Chatfuel service that answered.traceId: the request's trace ID. The same value is returned in thechatfuel-trace-idresponse header.data: for some business errors, a JSON string with details, for example which limit was reached.
Errors raised by the gateway itself, such as a syntax error or an unknown field, come without the wrapper and without a code; the message explains the problem. When some fields of a query fail and others succeed, data contains the successful parts and errors describes the rest.
How to read error codes
Collect codes from both levels so your code works with wrapped and unwrapped errors:
function errorCodes(errors = []) {
return errors.flatMap((error) => [
error.extensions?.code,
...(error.extensions?.errors ?? []).map((inner) => inner.extensions?.code),
]).filter(Boolean);
}
const body = await res.json();
const codes = errorCodes(body.errors);
if (codes.includes('Unauthorized')) {
// refresh or replace the token
}Authentication and permission errors
These two codes come with the message auth error:
Unauthorized: the request has no valid token. The token is missing, mistyped, revoked or regenerated, the header lacksBearer, or the virtual user was removed.NotEnoughPermissions: the token is valid, but its owner may not run this operation. Either a virtual user called an operation that needs a personal API token, or the role is too low, for example an Agent editing a flow. It also appears when the ID belongs to another bot.
Business error codes
Business errors come with the message service error and a code from the DefinedErrorCode enum of the public schema. Each reference page lists the codes its operations can return. The codes you will meet most often when working with virtual users:
| Code | Returned by | What to do |
|---|---|---|
VirtualUserRoleNotAllowed | createVirtualUser, changeBotMemberRoleV2 | Use the Editor or Agent role |
VirtualUserNameInvalid | createVirtualUser | Use a name of 1 to 100 characters |
VirtualUsersLimitReached | createVirtualUser | Remove unused virtual users; the limit is 20 per bot |
NotVirtualUser | regenerateVirtualUserToken | Pass the member ID of a virtual user, not of a teammate |
VirtualUserNotAllowed | Operations a virtual user can never perform, such as accepting an invite | Run the operation with a personal API token |
Other codes describe the data: ContactDoesNotExist, ContactNoteTooLong, BookingEndTimeBeforeStartTime, GoodsItemTitleNotUnique, FileTooBig and so on. Their names say what to fix.
Internal errors
InternalServerError, with the message internal server error, means the request failed on Chatfuel's side. Retry with exponential backoff. If it keeps failing, contact support through the chat in the bottom-right corner of the dashboard and include the traceId and the time of the request.
Common issues
"NotEnoughPermissions" for an operation that works in the dashboard
The dashboard runs as you, with your role. The API call runs as the virtual user, with its Editor or Agent role, and some operations are never available to virtual users. Check the operation's role in the reference, or run it with the personal API token.
"Unauthorized" right after rotating a token
regenerateVirtualUserToken and Regenerate token in the dashboard invalidate the old token immediately. Update every service that uses it.
The response has "errors" but HTTP status 200
That is normal for GraphQL. Treat a response as successful only when errors is absent.