> For the complete documentation index, see [llms.txt](https://docs.forepaas.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.forepaas.org/v2/getting-started/error-handling.md).

# Error Handling

Error codes, response envelopes, and recovery strategies for the ForeGate PaaS API

Requests can be rejected at two layers, and each layer speaks a slightly different dialect: the **Aliyun gateway** (signature/key validation, plain-text bodies plus diagnostic headers) and the **ForeGate service layer** (JSON envelopes). Knowing which layer produced an error is the fastest way to fix it.

## Response Envelope

Successful responses share the envelope:

```json
{
  "code": 0,
  "message": "ok",
  "data": { }
}
```

* `data` is an object, an array, or `null` depending on the endpoint.
* Pagination is endpoint-specific: deposit/withdraw history use `data.count` and `data.records`; market/account history use pagination fields inside `data`; search, trades, and open orders place pagination fields beside the envelope.
* Pagination starts at `page: 1`; the effective `pageSize` maximum is 100, and the gateway truncates larger values to 100.
* Proxy-generated JSON always uses `message`, not `msg`; proxy-generated success is `code: 0` and `message: ok`.

## HTTP Status Codes

| Status | Meaning                                                          |
| ------ | ---------------------------------------------------------------- |
| `200`  | Request succeeded                                                |
| `400`  | Invalid request parameters                                       |
| `401`  | Unauthorized (missing or invalid API key, signature, or session) |
| `404`  | Resource not found                                               |
| `415`  | Unsupported media type on a JSON-body endpoint                   |
| `500`  | Internal server error                                            |
| `502`  | Upstream unreachable or returned an unexpected status            |
| `504`  | Upstream request timeout                                         |

## Gateway-Layer Errors

These come from the Aliyun gateway itself, **before** your request reaches ForeGate. Bodies are plain text, not JSON.

### 400 — Invalid Signature

```
HTTP/1.1 400 Bad Request
x-ca-error-message: Invalid Signature. Server StringToSign:`...`

Invalid Signature
```

The `x-ca-error-message` header contains the string-to-sign **as the server computed it**. Diff it byte-by-byte against yours; see the debugging guidance in [Authentication](/v2/getting-started/authentication.md). The most common causes are uppercase signed-header names, missing empty `content-md5`/`content-type` lines on GET, unsorted query keys, and clock skew beyond \~15 minutes.

### 401 — Invalid Key

```
HTTP/1.1 401 Unauthorized

Invalid Key
```

The `x-ca-key` (APP Key) is unknown or not authorized for this API — distinct from a signature mismatch. Verify you are using the APP Key (not the API key) in `x-ca-key`.

## Service-Layer Errors

Once past the gateway, the ForeGate service layer returns JSON errors.

### Missing credentials

```json
{
  "code": 1401,
  "message": "unauthorized: Missing X-API-KEY header",
  "data": null
}
```

```json
{
  "code": 1401,
  "message": "unauthorized: Missing Cookie header",
  "data": null
}
```

### Invalid or expired session

```json
{
  "code": 1401,
  "message": "unauthorized: Invalid or expired session",
  "data": null
}
```

Re-register the user via [`POST /user/register`](/v2/api-reference/api-reference/user.md) to obtain a fresh session cookie, then retry.

### Parameter validation

Axum query-string deserialization failures are HTTP 400 `text/plain` responses, not JSON envelopes:

```
Failed to deserialize query string: missing field `marketId`
```

Body validation errors name the field and the expectation:

```json
{
  "code": 1001,
  "message": "bad request: LIMIT order requires numeric limitPrice",
  "data": null
}
```

### Gateway business codes

All proxy-generated JSON errors use stable business codes and message prefixes. For example:

```json
{
  "code": 1001,
  "message": "bad request: Missing or invalid positionId field",
  "data": null
}
```

```json
{
  "code": 1401,
  "message": "unauthorized: Missing X-API-KEY header",
  "data": null
}
```

Match on the HTTP status first and use the business code for programmatic classification:

| HTTP status | Business code | Meaning                                                        |
| ----------- | ------------: | -------------------------------------------------------------- |
| `200`       |           `0` | Proxy-generated success.                                       |
| `400`       |        `1001` | Invalid request input.                                         |
| `401`       |        `1401` | Authentication, timestamp-window, or nonce-replay failure.     |
| `404`       |        `1404` | Resource or route not found.                                   |
| `415`       |        `1415` | A JSON-body endpoint received another content type.            |
| `500`       |        `9999` | Proxy serialization, I/O, parsing, or configuration failure.   |
| `502`       |        `2002` | Upstream service could not be reached.                         |
| `502`       |        `2003` | Upstream service returned an unexpected error/status.          |
| `504`       |        `2001` | Upstream request timed out.                                    |
| `200`       |        `4054` | Upstream business failure: CLOB order book is not initialized. |

The MFA service can also return upstream-defined business errors for invalid codes, expired sessions, locking, rate limits, or disabled methods. Those responses keep the standard `{code,message,data}` shape but are not rewritten into the proxy codes above.

### Resource not found

```json
{
  "code": 1404,
  "message": "resource not found: User not found",
  "data": null
}
```

## WebSocket Errors

Handshake failures surface as the HTTP errors above (the upgrade is a signed GET). After a successful upgrade, an unreachable upstream is signaled with a close frame: `Close(1011, "upstream unavailable")` — including cases where the upstream rejects an expired session cookie. See the [WebSocket API](/v2/advanced/websocket-api.md#handshake-errors-all-channels).

## Recovery Strategies

| Symptom                                                                    | Action                                                                                                                    |
| -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `400 Invalid Signature` (gateway)                                          | Fix the string-to-sign using `x-ca-error-message`; do not retry unchanged requests.                                       |
| `401 Invalid Key` / `Missing X-API-KEY`                                    | Fix credentials/headers; retrying without a change cannot succeed.                                                        |
| `401` with business code `1401` for a missing, invalid, or expired session | Re-register the user, capture the new `Set-Cookie`, retry once.                                                           |
| `400` validation errors                                                    | Fix the named field; these are deterministic.                                                                             |
| `500`, `502`, or `504` (transient)                                         | Retry idempotent requests with exponential backoff and a capped attempt count; reconcile state before retrying mutations. |
| WebSocket `Close(1011)`                                                    | Reconnect with backoff; re-seed order-book state from the REST snapshot after reconnecting.                               |

{% hint style="info" %}
**Log the diagnostics:** for every failed request, persist the HTTP status, the response body, and — for gateway errors — the `x-ca-error-message` header. That single header resolves the vast majority of integration issues.
{% endhint %}
