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

# Error Codes and Troubleshooting for Upside API

> Reference for HTTP-level error codes and business-level error messages returned by the Upside API, with common troubleshooting guidance.

Upside returns errors at two levels: **HTTP-level errors** that appear in the top-level `status: "error"` response, and **business-level errors** that appear inside `response.data.statuses[]` even when `status` is `"ok"`. Both levels are documented here.

## HTTP-Level Error Codes

These errors are returned with a non-200 HTTP status code when the server rejects the request before or during processing. The response body contains `status: "error"`, a machine-readable `code`, and a human-readable `message`.

| Error Code               | HTTP Status | Description                                                                                      |
| ------------------------ | ----------- | ------------------------------------------------------------------------------------------------ |
| `BAD_REQUEST`            | 400         | Malformed request — missing required fields, invalid JSON syntax, or unexpected field types      |
| `UNKNOWN_ACTION`         | 400         | The `action.type` value is not recognized by the server                                          |
| `SIGNATURE_INVALID`      | 401         | ECDSA signature recovery failed, or the recovered address does not match the registered account  |
| `ACCOUNT_ALREADY_EXISTS` | 400         | The address is already registered; `registerAccount` cannot be called twice for the same address |
| `INVITE_CODE_INVALID`    | 403         | The invite code is invalid (`NOT_FOUND`) or has already been used (`ALREADY_USED`)               |
| `BATCH_TOO_LARGE`        | 400         | The `orders[]` or `cancels[]` array contains more than 10 items                                  |
| `RATE_LIMITED`           | 429         | Too many requests from this IP or account; back off and retry                                    |
| `DOWNSTREAM_TIMEOUT`     | 504         | The backend matching engine did not respond within 5 seconds; the operation was not applied      |
| `INTERNAL_ERROR`         | 500         | Unexpected server-side error; contact Upside support with the `requestId`                        |

## Business-Level Errors

These errors appear inside `response.data.statuses[]` when the request envelope is valid and authenticated, but the matching engine or risk engine rejects one or more operations within the batch. The outer `status` is `"ok"` and the HTTP status is 200.

| Message                                   | Cause                                                                                                                                   |
| ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `signer <addr> has no registered account` | The signing address has not been registered. Call `registerAccount` before placing orders.                                              |
| `orderId not found`                       | The order has already been cancelled, fully filled, or was never created with that ID.                                                  |
| `size must be positive`                   | The order quantity is zero or negative.                                                                                                 |
| `price <n> exceeds maxTicks <max>`        | The order price exceeds the allowed maximum. On testnet the limit is `10000`.                                                           |
| `action.orders size N exceeds max 10`     | The `orders[]` array contains more than 10 items. Split the batch into multiple requests.                                               |
| `timeout`                                 | The backend processing timed out. The operation was not applied. It is safe to retry.                                                   |
| `share margin group is FROZEN`            | The account is in portfolio margin mode and the share group is frozen. Only `reduceOnly` orders are accepted while the group is frozen. |

## Troubleshooting

<Accordion title="I keep getting SIGNATURE_INVALID">
  This is the most common error when integrating for the first time. Work through this checklist:

  1. **Right signing path** — Funds/permission actions (`registerAccount`, `approveAgent`, `revokeAgent`, `lockCollateral`, `unlockCollateral`, `transferBetweenDeployers`) use the EIP-712 **typed** struct; everything else uses the **Agent** path. Signing an action via the wrong path always fails. See [Authentication](/guide/authentication).
  2. **Canonical JSON (Agent path)** — Keys must be sorted alphabetically with compact separators and no whitespace: `json.dumps(action, sort_keys=True, separators=(",", ":"))`. A single extra space produces a different `actionHash`.
  3. **Correct domain & nonce encoding** — Use the fixed domain (`name="Exchange"`, `version="1"`, `chainId=9767`, `verifyingContract=0x0`). The nonce is a big-endian **8-byte** suffix inside the Agent `actionHash`, but a **32-byte** `uint64` field in a typed struct — mixing these up is a common cause.
  4. **No double-hashing** — The EIP-712 `digest` is already the final hash. Pass the 32-byte digest directly to the signing function (`prehash = false`); do not hash again.
  5. **Correct `v` value** — Ensure `v = sig.v if sig.v >= 27 else sig.v + 27`. Some libraries return `v` as 0 or 1; you must add 27.
  6. **Right private key** — The `SIGNATURE_INVALID` message includes the recovered address. If it doesn't match your expected address, you are signing with a different private key than the one whose address you registered.
</Accordion>

<Accordion title="My order returns status ok but has an error in statuses">
  This is a business-level rejection, not an HTTP error. The request was correctly signed and delivered to the matching engine, but the engine rejected the order.

  Check `response.data.statuses[0].error` for the rejection reason. Common causes:

  * **`size must be positive`** — You passed `"s": "0"` or a negative string.
  * **`price <n> exceeds maxTicks`** — On testnet, price must be ≤ 10000.
  * **`signer has no registered account`** — You need to call `registerAccount` first.
  * **`orderId not found`** — The `oid` you tried to cancel doesn't exist or was already filled.

  Always iterate over the entire `statuses` array when placing batch orders — some items in the batch may succeed while others fail.
</Accordion>

<Accordion title="I get DOWNSTREAM_TIMEOUT">
  A `DOWNSTREAM_TIMEOUT` (HTTP 504) means the backend matching engine did not return a result within the server's 5-second timeout window. Critically, this means the operation was **not applied** — you will not find a new order or cancellation as a result of that request.

  **What to do:**

  1. Wait 1–2 seconds.
  2. Query `POST /info` with `userOrders` to confirm the current state of your orders.
  3. If the order does not exist, retry the request with a fresh nonce.
  4. If you continue to see timeouts, check the Upside status page or contact support with your `requestId`.
</Accordion>

<Accordion title="registerAccount fails with ACCOUNT_ALREADY_EXISTS">
  This means the address has already been registered in this environment. You do not need to register again — proceed directly to placing orders.

  If you are generating a new keypair each time in your test scripts, each new address will need its own `registerAccount` call. Consider persisting your test wallet's private key between runs.
</Accordion>

<Accordion title="registerAccount fails with INVITE_CODE_INVALID">
  Some environments require a valid invite code to register. Make sure you:

  1. Place the `inviteCode` field at the **top level** of the envelope — not inside the `action` object.
  2. Do **not** include `inviteCode` inside the signed message (it is outside `action`).
  3. Check whether the code was already used (`ALREADY_USED`) or is simply wrong/expired (`NOT_FOUND`).

  Contact the Upside team to obtain a valid invite code for restricted environments.
</Accordion>
