Skip to content

Errors

This content is not available in your language yet.

A GraphQL error comes back in the errors array of the JSON body. Each entry has a human message and a machine-readable extensions.code; branch on the code, never on the message text, which can change. Most errors arrive with HTTP status 200, so check errors on every response, not only on non-2xx ones. A few are refused before the operation runs and come back with HTTP 400 (marked below).

{
"errors": [
{
"message": "Agent #7 not found",
"locations": [{ "line": 2, "column": 3 }],
"path": ["sdkStart"],
"extensions": {
"code": "NOT_FOUND",
"status": 404,
"originalError": {
"message": "Agent #7 not found",
"error": "Not Found",
"statusCode": 404
}
}
}
],
"data": null
}

extensions.originalError repeats the underlying refusal (for input validation its message is the list of every failed rule). extensions.status is present on NOT_FOUND, CONFLICT, BAD_GATEWAY and INTERNAL_SERVER_ERROR. A few refusals add their own extensions.originalError.code for a client that wants to branch further, for example OUTBOUND_URL_REFUSED (below).

extensions.codeHTTPReal example messageUsual causeRetry?
UNAUTHENTICATED200Invalid API keyMissing, wrong, expired or revoked credential, or the wrong kind of credential for the operation. See the Authentication cheat sheetNo, fix the credential
FORBIDDEN200Platform is not specified!The x-huat-platform: customer header is missing, a member called an owner-only operation, or the session token belongs to another sessionNo
BAD_REQUEST200Session 4211 is not active (status: ended)The input broke a rule of the operation: a field over its limit, two arguments that cannot be combined, a resource in the wrong stateNo, change the input
BAD_USER_INPUT400Variable "$input" got invalid value { agentId: 7, customerId: "ticket-1001" }; Field "customerId" is not defined by type "SdkStartInput".The variables do not match their GraphQL types: an unknown field, a missing required field, a wrong type or a value outside an enum. A few operations also use it, with HTTP 200, for their own checks (for example an invalid workflow graph)No, change the variables
NOT_FOUND200Agent #7 not foundThe id does not exist in your workspace. Another workspace’s id answers the same, by designNo
CONFLICT200Approval #118 was already approved by user #3 at 2026-10-12T03:21:44.000ZThe resource changed state first, for example a request already decided or expiredNo, re-read the resource
GRAPHQL_VALIDATION_FAILED400Cannot query field "rating" on type "SdkEvaluationResult".The query asks for a field or argument that does not exist, or nests deeper than 7 levelsNo, fix the query
QUERY_TOO_COMPLEX(refused before running)Query is too complex: 61. Maximum allowed complexity: 50The query selects more than 50 fields in total. Select only what you needNo, trim the query
BAD_GATEWAY200The MCP server could not list its tools: connection refused: fetch failed (with extensions.status 502)Your own MCP server could not be reached or did not answer properly (listMcpTools). The fault is on that server’s side, not Wetel’sYes, once the server is fixed
TOO_MANY_REQUESTS200Too many requests. Try again in about 2 minutes. (with extensions.status 429 and extensions.retryAfterSeconds; on staging, production rollout pending; before: INTERNAL_SERVER_ERROR ThrottlerException: Too Many Requests)A rate limit refused the call. Wait retryAfterSecondsYes, after the wait
INTERNAL_SERVER_ERROR200ThrottlerException: Too Many Requests (with extensions.status 429)A rate limit (status 429, see Rate limiting) or an unexpected failure on our sideYes, with backoff

Each operation’s reference page lists the errors it typically returns, with the full JSON body: for example Sessions and messages and Approvals.

Live in production since 2026-10-21. A URL Wetel would call out to (an MCP connector’s serverUrl, a custom action’s url, an agent’s externalSyncUrl, a webhook node’s url) that does not parse, does not resolve, or resolves to a private or reserved address answers BAD_REQUEST with extensions.originalError.code OUTBOUND_URL_REFUSED and extensions.originalError.reason INVALID_URL, UNRESOLVABLE_HOST or PRIVATE_ADDRESS. Before, it answered INTERNAL_SERVER_ERROR. Change the URL; do not retry. See Refused URLs and an unreachable MCP server.

Live in production since 2026-10-23. A request with a Content-Encoding other than identity is refused with HTTP 415 before GraphQL runs, so there is no errors array: the body is {"statusCode":415,"code":"UNSUPPORTED_CONTENT_ENCODING",...} (the public edge may answer a plain 415 page). Resend without Content-Encoding; see Send plain request bodies.

  1. Read the body as JSON whatever the HTTP status.
  2. If errors is present and non-empty, take errors[0].extensions.code.
  3. Retry only INTERNAL_SERVER_ERROR, with exponential backoff; when extensions.status is 429, wait for the rate-limit window (usually 60 seconds) to pass.
  4. For every other code, log the full errors entry and fix the request: retrying the same request gives the same answer.

The generated samples on every reference page do steps 1 and 2 already. For background on how codes are produced, see Error Handling and Status Codes.