> ## Documentation Index
> Fetch the complete documentation index at: https://docs.helix-db.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Helix Cloud gateway errors

> Use stable Helix Cloud error codes, HTTP statuses, and SDK error metadata

<div className="flex flex-wrap gap-2"><Badge color="gray" size="sm">Reference</Badge></div>

Helix Cloud query failures use one JSON envelope:

```json theme={"languages":{"custom":["languages/helixql.json"]}}
{
  "error": "query_timeout",
  "msg": "query exceeded its wall-clock limit"
}
```

* `error` is a stable, lower-snake-case code. Branch on this field.
* `msg` is a human-readable diagnostic. Log it, but do not parse it or depend on
  its exact text.
* The HTTP status remains part of the contract. Use it with `error` when deciding
  whether and how to retry.
* `write_outcome_unknown` adds `"retryable": false`. Cypher statement errors add a
  `details` object; see [Cypher errors](#cypher-errors).

The table below lists codes produced by the Cloud gateway itself. Errors raised by the
database engine behind it use the same envelope; see the
[query error reference](/database/helix-db/query-guides/error-handling) for those codes.

## Gateway error reference

| HTTP | `error` | Typical `msg` | Meaning | Retry guidance |
| -: | - | - | - | - |
| 400 | `invalid_query_json` | `parse error: <decoder diagnostic>` | The request body is not valid query JSON. | Fix the request. |
| 400 | `invalid_request` | A request-specific diagnostic | A required header or request option is missing, malformed, or invalid. | Fix the request. |
| 400 | `tenant_id_required` | `x-helix-tenant-id or x-helix-database-id is required in GA mode` | A Cloud request did not identify its database. | Use the correct database-scoped Cloud endpoint and configuration. |
| 400 | `tenant_id_not_allowed` | `x-helix-tenant-id and x-helix-database-id are not allowed in cluster mode` | A tenant/database header was sent to an endpoint that does not accept it. | Remove the header or use the correct endpoint. |
| 400 | `active_text_mutation_limit_exceeded` | `db error: Active text mutation exceeds <resource>: observed <usage>, limit <bound>. This is a hard per-document limit; shorten the indexed text.` | One indexed text document exceeds a hard per-document admission limit; graph changes are not committed. | Shorten the text before retrying; see [Limits](/database/helix-cloud/operate/limits#active-text-mutation-admission). |
| 401 | `unauthorized` | `unauthorized` | The supplied API key is unknown or no longer active. | Refresh or replace the key. |
| 402 | `tenant_disabled` | `tenant query processing is disabled because credit is exhausted` | Query processing is disabled because the tenant has exhausted its credit. | Resolve the account state before retrying. |
| 403 | `forbidden` | `forbidden` | The key is valid but cannot perform this operation. | Use a key with the required permission. |
| 408 | `query_timeout` | `query exceeded its wall-clock limit` | The query exceeded its wall-clock limit. | Reconcile timed-out writes before considering a retry. |
| 409 | `transaction_conflict` | `request conflicted with a concurrent write; please retry` | A concurrent write prevented the transaction from committing. | Retry the whole idempotent transaction with bounded backoff. |
| 413 | `payload_too_large` | `request body exceeds the maximum allowed size` | The query request exceeds the gateway body-size limit. | Reduce the request size. |
| 429 | `rate_limited` | `rate limit exceeded` | The database's request bucket has no token available. | Honor `Retry-After`; see [Limits](/database/helix-cloud/operate/limits). |
| 500 | `internal_error` | An internal or backend diagnostic | An unexpected gateway or backend error occurred. | Retry only if the operation is safe; contact support if persistent. |
| 503 | `backend_unavailable` | `Backend unavailable` | No eligible database backend is currently available. | Retry with bounded exponential backoff and jitter. |
| 503 | `rate_limit_unavailable` | `tenant rate limit is unavailable` | The gateway cannot make a safe rate-limit decision. | Retry with bounded exponential backoff and jitter. |
| 503 | `failover_wait_unavailable` | `managed writer transition wait is unavailable` | A write arrived during a writer transition that the gateway could not wait out, so it did not send the write. | Honor `Retry-After` (1 second), then retry. |
| 503 | `write_outcome_unknown` | `write outcome is unknown; the operation was not replayed` | The gateway sent a write but cannot tell whether it committed, for example because its deadline passed or the writer changed. The body includes `"retryable": false`. | Do not resubmit automatically. Reconcile first; see [Timed-out writes](#timed-out-writes). |

The text in `msg` can include request-specific details. The `error` values and
HTTP statuses above are the compatibility surface.

## Cypher errors

`POST /v2/cypher` and `POST /v2/cypher/explain` use the same envelope and gateway
codes. A failed statement also carries a `details` object:

```json theme={"languages":{"custom":["languages/helixql.json"]}}
{
  "error": "resource_limit",
  "msg": "expression temporaries exceed the query memory budget",
  "details": { "detail": "memory_limit", "phase": "runtime", "span": null }
}
```

The category in `error` and the condition in `details.detail` are lower snake case
codes, listed in the [query error reference](/database/helix-db/query-guides/error-handling#cypher-errors).
A `resource_limit` (HTTP 429) is a per-query budget, not the database's request
rate: resending the same statement fails again, so reduce the work instead of
honoring `Retry-After`. Check `error` to tell it apart from `rate_limited`.

## SDK access

Official SDKs decode `error` and `msg` into separate stable-code and diagnostic
fields. Non-JSON responses from older endpoints and intermediaries remain
available as readable diagnostics. Rust and TypeScript also retain the raw
response body separately.

| SDK | HTTP status | Stable code | Diagnostic | Raw response |
| - | - | - | - | - |
| Rust | `HelixError::status_code()` | `HelixError::remote_code()` | `HelixError::remote_message()` | `HelixError::raw_response_body()` |
| TypeScript | `HelixError.statusCode` | `HelixError.code` | `HelixError.serverMessage` | `HelixError.rawBody` |
| Python | `HelixError.status_code` | `HelixError.code` | `HelixError.details` | Not exposed separately |
| Go | `HelixError.StatusCode` | `HelixError.Code` | `HelixError.Details` | Not exposed separately |

The current SDK error objects do not expose response headers, including
`Retry-After`. Use direct HTTP or an application transport that retains headers
when the exact Cloud rate-limit delay is required.

Branch on the stable code while retaining the diagnostic:

<CodeGroup>
  ```rust Rust theme={"languages":{"custom":["languages/helixql.json"]}}
  if let Err(error) = client.query::<MyResponse>(request).send().await {
      if error.remote_code() == Some("query_timeout") {
          eprintln!("{}", error.remote_message().unwrap_or("query timed out"));
      }
  }
  ```

  ```ts TypeScript theme={"languages":{"custom":["languages/helixql.json"]}}
  import { HelixError } from "@helix-db/helix-db";

  try {
    await client.query(request).send();
  } catch (cause) {
    if (cause instanceof HelixError && cause.code === "query_timeout") {
      console.error(cause.serverMessage);
    }
    throw cause;
  }
  ```

  ```python Python theme={"languages":{"custom":["languages/helixql.json"]}}
  try:
      client.query(request)
  except HelixError as error:
      if error.code == "query_timeout":
          print(error.details)
  ```

  ```go Go theme={"languages":{"custom":["languages/helixql.json"]}}
  err := client.Exec(ctx, request, &response)
  var helixErr *helix.HelixError
  if errors.As(err, &helixErr) &&
  	helixErr.Code == helix.QueryErrorCode("query_timeout") {
  	log.Print(helixErr.Details)
  }
  ```

  ```json JSON theme={"languages":{"custom":["languages/helixql.json"]}}
  {
    "error": "query_timeout",
    "msg": "query exceeded its wall-clock limit"
  }
  ```
</CodeGroup>

## Timed-out writes

An HTTP `408` cancels the gateway's wait, but a write can race with durable
commit. A write that the gateway already sent to the writer returns `503` with
`write_outcome_unknown` and `"retryable": false` instead. In both cases, treat the
outcome as unknown. Reconcile using an application identity or idempotency key
before submitting the write again.

## Migration from the previous shape

Some earlier responses used `error` for diagnostic text and `code` for the
machine-readable value, while others returned only `error`. For Cloud gateway
responses, migrate from this shape:

```json theme={"languages":{"custom":["languages/helixql.json"]}}
{
  "error": "query exceeded its wall-clock limit",
  "code": "QUERY_TIMEOUT"
}
```

to `error` as the lower-snake-case code and `msg` as diagnostic text. Earlier
gateways also reported unknown write outcomes and unavailable failover waits in
that shape, as `{"code":"WRITE_OUTCOME_UNKNOWN","error":"<message>","retryable":false}`
and `"code":"FAILOVER_WAIT_UNAVAILABLE"`. They are now `write_outcome_unknown` and
`failover_wait_unavailable` in the envelope above, and Cypher categories and
details, formerly upper camel case such as `ResourceLimit`, are lower snake case.
Current SDKs read both shapes. Keep a readable diagnostic fallback for
intermediaries and older self-hosted endpoints that do not return the Cloud
envelope.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.