Errors
Common public error codes and meanings
Wallet-Facing Errors
| Situation | Recommended response |
|---|---|
Player does not have funds for reserve_cash | HTTP 422 with code: "insufficient_funds" |
| Phoenix signature is invalid | HTTP 401 or 403 |
| Request body is malformed | HTTP 400 |
| Same idempotency key is still processing | HTTP 409 |
| Same idempotency key is reused with a different payload | HTTP 422 |
| Temporary operator outage | HTTP 503 |
Player-Facing Phoenix Reasons
When a player command is rejected, the command reply carries a structured reason:
{
"kind": "command",
"outcome": "rejected",
"reason": { "code": "validation", "message": "insufficient funds" }
}reason.code is a closed taxonomy. Branch on it in client code; never parse reason.message,
which is a human-readable string for display and logs.
reason.code | Meaning |
|---|---|
validation | Request was well-formed but invalid for the market or order (bad amount, price, or stake, or the wallet declined the reservation) |
not_found | Referenced market does not exist or is out of the operator environment |
forbidden | Action is not allowed (operator not active, currency not supported, not the order owner) |
conflict | Request conflicts with current state (market closed, paused, resolved, not yet open, or idempotency key reused with different parameters) |
rate_limited | Client is sending requests too quickly; may include retry_after_ms |
idempotency_required | Mutation requires an idempotency key and none was provided |
unknown_mutation | The requested mutation is not a recognized command |
internal | Phoenix hit an unexpected internal condition; retry later |
The most common reason.message strings, by code:
reason.message | code | When |
|---|---|---|
insufficient funds | validation | Operator wallet declined the cash reservation. Transient or unreachable-wallet failures are retried internally and never surface as a distinct reason |
invalid order | validation | Order intent failed validation (quantity, price, or budget) |
a market order cannot carry a limit price | validation | A MARKET order included a limit price |
insufficient position to sell | validation | Sell exceeds the player's position |
order is below the minimum order size | validation | Stake under the operator's minimum |
order exceeds the maximum order size | validation | Stake over the operator's maximum |
amount has more decimals than the currency allows | validation | Stake precision exceeds the currency |
market not found | not_found | Market does not belong to this operator environment or does not exist |
market not available | not_found | Market has no published definition in this environment |
operator is not active for trading | forbidden | Operator is suspended or not enabled |
currency not supported by this operator | forbidden | Currency is not configured for the operator |
not the order owner | forbidden | Cancel targeted another player's order |
market is closed | conflict | Market is no longer accepting orders |
trading is paused | conflict | Market is paused |
market is not yet open | conflict | Market definition is not yet published |
market is closed for new positions | conflict | Market is resolved |
idempotency key reused with different parameters | conflict | Same idempotency key sent with a different order payload |
A retry under the same idempotency key with identical parameters is safely de-duplicated: it returns the original order with no error. Only a key reused with different parameters conflicts.
Show friendly copy to players. Keep reason.code and reason.message in logs for support.
Operator API Errors
| HTTP status | Meaning |
|---|---|
401 | Signature, timestamp, operator code, or key verification failed |
404 | Resource not found within the authenticated operator scope |
422 | Request was authenticated but invalid for the market state or schema |