All errors follow a consistent JSON structure:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable description of the error"
}
}
The HTTP status code indicates the error category, while the code field provides a machine-readable identifier for programmatic handling.
Error Codes Reference
Authentication Errors
| Code | HTTP Status | Description |
|---|
INVALID_API_KEY | 401 | Missing, invalid, or expired API key |
SIGNATURE_ERROR | 401 | Invalid wallet signature for trading operations |
SESSION_EXPIRED | 401 | Agent/signer session has expired; re-approve |
Validation Errors
| Code | HTTP Status | Description |
|---|
INVALID_PARAMS | 400 | Request parameters failed validation |
MISSING_REQUIRED_FIELD | 400 | A required field was not provided |
Provider Errors
| Code | HTTP Status | Description |
|---|
UNSUPPORTED_PROVIDER | 400 | Provider does not exist or does not support this operation |
UNSUPPORTED_NETWORK | 400 | Network (mainnet/testnet) not available for this provider |
PROVIDER_ERROR | 502 | Upstream provider returned an unexpected error |
PROVIDER_UNAVAILABLE | 503 | Upstream provider is temporarily unreachable |
Trading Errors
| Code | HTTP Status | Description |
|---|
INSUFFICIENT_MARGIN | 422 | Not enough margin/collateral for this order |
ORDER_NOT_FOUND | 404 | Order ID does not exist or has already been filled/canceled |
ORDER_REJECTED | 422 | Order was rejected by the exchange |
INVALID_ORDER | 400 | Order parameters are invalid (e.g., bad side, type) |
PRICE_TOO_FAR | 422 | Limit price is too far from mark price |
SIZE_TOO_SMALL | 422 | Order size is below the minimum for this market |
MAX_LEVERAGE_EXCEEDED | 422 | Requested leverage exceeds the maximum for this market |
POSITION_NOT_FOUND | 404 | No open position found for the specified market |
REDUCE_ONLY_REJECTED | 422 | Reduce-only order would increase position size |
TOO_MANY_ORDERS | 422 | Maximum open orders limit reached |
General Errors
| Code | HTTP Status | Description |
|---|
RATE_LIMITED | 429 | Rate limit exceeded |
NOT_FOUND | 404 | Requested resource does not exist |
INTERNAL_ERROR | 500 | Unexpected server error |
Handling Errors
async function placeOrder(params: OrderParams) {
const response = await fetch("https://api.perps.studio/v1/perps/hyperliquid/orders", {
method: "POST",
headers: {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify(params),
});
if (!response.ok) {
const { error } = await response.json();
switch (error.code) {
case "INSUFFICIENT_MARGIN":
console.error("Not enough margin. Deposit more collateral.");
break;
case "RATE_LIMITED":
const retryAfter = response.headers.get("Retry-After");
console.error(`Rate limited. Retry in ${retryAfter}s`);
break;
case "PROVIDER_UNAVAILABLE":
console.error("Exchange is temporarily down. Retry later.");
break;
default:
console.error(`Error ${error.code}: ${error.message}`);
}
return null;
}
return response.json();
}
Provider-Specific Errors
When an upstream provider returns an error, the Provider API wraps it in a PROVIDER_ERROR or a more specific code when possible. The original provider error message is preserved in the message field.
{
"error": {
"code": "ORDER_REJECTED",
"message": "Hyperliquid: Order would immediately cross. Use IOC or adjust price."
}
}
Provider error messages are prefixed with the provider name so you can always tell which exchange generated the error.