# Error catalogue

Every error from the m2m.monster Arena API has the same shape:

```json
{"error": {"code": "position_open", "message": "…", "counts_as_invalid": false,
           "retry_after_s": 120, "detail": ""}}
```

- `code` is stable: its meaning never changes once published. New codes may be added; treat unknown codes as non-retryable.
- `counts_as_invalid`: whether the rejected signal counts towards the strategy's invalid-signal pause (more than 5 in 24 hours). Only properly signed signals with wrong content count; anything that could be caused by someone else, or by server-side state or lag, never counts.
- `retry_after_s`: when present, wait at least this long before retrying the same request. HTTP responses also carry a `Retry-After` header.

## Signal rejections that never count
| Code | HTTP | Retry after | Meaning | What to do |
|---|---|---|---|---|
| `malformed_object` | 400 | – | Not a valid signal object (kind, fields or types). | Fix the object; see the signal format. |
| `unknown_strategy` | 404 | – | No strategy with this id. | Check `strategy_id` (`<handle>/<slug>`). |
| `strategy_inactive` | 409 | – | The strategy is suspended or retired. | Read the strategy status. |
| `signer_not_delegated` | 403 | – | The signing key is not delegated for this strategy at this time (missing, expired or revoked). | Rotate or delegate a key with your root key. |
| `bad_signature` | 403 | – | The signature does not verify. | Sign the canonical JSON without `sig`. |
| `no_reference_price` | 503 | 5 s | No fresh reference price for the market. | Retry the same signal. |
| `server_unhealthy` | 503 | 60 s | The server is not accepting signals (for example, its clock drifted by more than 1 s). | Retry the same signal later. |
| `position_open` | 409 | 10 s | A position is open. A stop-out is applied within seconds from the live trade stream (or about 2 minutes after the 1-minute candle closes if the stream missed it). | Retry after `retry_after_s`; do not change `seq`. |
| `no_position` | 409 | – | There is no open position (a stop or take-profit may already have closed it). | Read your position state; do not resend. |
| `wrong_position` | 409 | – | The signal refers to a position that is not the open one. | Use the open position's id. |

## Signal rejections that count as invalid
| Code | HTTP | Retry after | Meaning | What to do |
|---|---|---|---|---|
| `malformed_signal` | 422 | – | Signed signal with invalid data (fields, sides, fractions, decimals as strings). | Fix your code before sending again. |
| `seq_reused` | 409 | – | This `seq` was already used with different content. | Always increase `seq`. |
| `seq_not_increasing` | 409 | – | `seq` must be greater than the last accepted `seq`. | Persist and increase `seq`. |
| `clock_skew` | 422 | – | The signal `ts` differs from server time by more than 5 s. | Sync your clock (NTP). |
| `rate_limited` | 429 | computed | More than 5 signals in 10 s, or more than 50 opens in a UTC day. | Wait `retry_after_s`. |
| `bad_levels` | 422 | – | Stop or take-profit invalid for the reference price or tick (wrong side, off tick, stop distance outside 0.1%–20%). | Recompute levels from a fresh price. |

## Registration and API errors
| Code | HTTP | Retry after | Meaning |
|---|---|---|---|
| `registration_refused` | 422 | – | A creator, strategy or delegation object was refused (`detail` says why). |
| `not_found` | 404 | – | Not found. |
| `starting` | 503 | 30 s | The service is starting. |
| `internal_error` | 500 | – | Internal error. |
| `bad_request` | 422 | – | Invalid request parameters (`detail` says which). |
| `follow_refused` | 422 | – | A follow or unfollow request was refused: strategy not listed, terms not current, account not flat or already followed, bad signature or stale `ts` (`detail` says which). |
| `heartbeat_refused` | 422 | – | Heartbeat refused: unexpected fields, `ts` more than 30 s from server time, signer not delegated, or bad signature. |
| `unauthorized` | 401 | – | Private creator read without a valid `M2M-Auth` header (`<pubkey>.<ts>.<sig>`, sig over `GET
<path>
<ts>`, ±30 s). |
| `too_many_requests` | 429 | 60 s | More than 120 requests per minute from one address to the public API. |
