Error Reference
Complete list of API error codes and how to handle them
Error Response Format
All API errors return a JSON response with the following structure:
{
"detail": "Error message describing what went wrong",
"error_code": "specific_error_code",
"request_id": "req_abc123"
}| Field | Type | Description |
|---|---|---|
detail | string | Human-readable error message |
error_code | string | Machine-readable error code |
request_id | string | Unique request identifier for support |
HTTP Status Codes
| Status Code | Meaning |
|---|---|
400 | Bad Request - Invalid parameters |
401 | Unauthorized - Invalid or missing API key |
403 | Forbidden - No permission for this resource |
404 | Not Found - Resource doesn't exist |
409 | Conflict - Duplicate resource (e.g., intent_id) |
422 | Unprocessable Entity - Validation error |
429 | Too Many Requests - Rate limit exceeded |
500 | Internal Server Error - Server-side error |
503 | Service Unavailable - Service temporarily down |
Client Errors (4xx)
400 Bad Request
Cause: Invalid request parameters
Example:
{
"detail": "limit_price is required for limit orders",
"error_code": "missing_limit_price"
}Solution: Add missing required fields
# Missing limit_price
intent = TradeIntentRequest(
order_type=OrderType.LIMIT # Missing limit_price!
)
# Correct
intent = TradeIntentRequest(
order_type=OrderType.LIMIT,
limit_price=Decimal("175.00")
)401 Unauthorized
Cause: Invalid or missing API key
Example:
{
"detail": "Invalid API key",
"error_code": "unauthorized"
}Solution: Check your API key
# Verify API key is valid
client = SnipeRouteClient(
api_key=os.getenv("SNIPEROUTE_API_KEY")
)403 Forbidden
Cause: API key doesn't have permission
Example:
{
"detail": "This API key does not have permission for this resource",
"error_code": "forbidden"
}Solution: Use the correct API key type (test vs live)
404 Not Found
Cause: Resource doesn't exist
Example:
{
"detail": "Trade Intent not found",
"error_code": "not_found"
}Solution: Verify the resource ID
try:
intent = await client.get_intent_by_external_id("trade_001")
except NotFoundError:
print("Intent not found")409 Conflict
Cause: Duplicate intent_id
Example:
{
"detail": "Trade Intent with this intent_id already exists",
"error_code": "duplicate_intent_id"
}Solution: Use unique intent_id for each submission
import uuid
# Generate unique ID
intent_id = f"trade_{uuid.uuid4()}"422 Unprocessable Entity
Cause: Validation error
Example:
{
"detail": [
{
"loc": ["body", "quantity"],
"msg": "ensure this value is greater than 0",
"type": "value_error.number.not_gt"
}
],
"error_code": "validation_error"
}Solution: Fix validation errors
# Invalid quantity
quantity=Decimal("0") # Must be > 0
# Correct
quantity=Decimal("10")429 Too Many Requests
Cause: Rate limit exceeded
Example:
{
"detail": "Rate limit exceeded. Retry after 60 seconds.",
"error_code": "rate_limit_exceeded",
"retry_after": 60
}Solution: Implement retry with backoff
import asyncio
from sniperoute.exceptions import RateLimitError
async def submit_with_retry(client, intent):
while True:
try:
return await client.create_intent(intent)
except RateLimitError as e:
retry_after = e.retry_after or 60
await asyncio.sleep(retry_after)Server Errors (5xx)
500 Internal Server Error
Cause: Server-side error
Example:
{
"detail": "Internal server error",
"error_code": "internal_server_error",
"request_id": "req_abc123"
}Solution: Retry with exponential backoff
import asyncio
async def submit_with_backoff(client, intent, max_retries=3):
for attempt in range(max_retries):
try:
return await client.create_intent(intent)
except SnipeRouteAPIError as e:
if e.status_code >= 500:
if attempt == max_retries - 1:
raise
wait_time = 2 ** attempt
await asyncio.sleep(wait_time)
else:
raise503 Service Unavailable
Cause: Service temporarily unavailable
Example:
{
"detail": "Service temporarily unavailable",
"error_code": "service_unavailable"
}Solution: Retry after a delay
Broker-Specific Errors
Insufficient Funds
{
"detail": "Broker rejected order: Insufficient buying power",
"error_code": "broker_error",
"broker_error_code": "insufficient_funds"
}Solution: Check account balance
Invalid Symbol
{
"detail": "Broker rejected order: Symbol not found",
"error_code": "broker_error",
"broker_error_code": "invalid_symbol"
}Solution: Verify symbol is valid for the broker
Market Closed
{
"detail": "Broker rejected order: Market is closed",
"error_code": "broker_error",
"broker_error_code": "market_closed"
}Solution: Check market hours or use extended_hours: true
Trading Halted
{
"detail": "Broker rejected order: Trading halted for this symbol",
"error_code": "broker_error",
"broker_error_code": "halted"
}Solution: Wait for trading to resume
Validation Errors
Missing Required Field
{
"detail": [
{
"loc": ["body", "limit_price"],
"msg": "field required",
"type": "value_error.missing"
}
]
}Invalid Field Type
{
"detail": [
{
"loc": ["body", "quantity"],
"msg": "value is not a valid decimal",
"type": "type_error.decimal"
}
]
}Invalid Enum Value
{
"detail": [
{
"loc": ["body", "side"],
"msg": "value is not a valid enumeration member; permitted: 'buy', 'sell'",
"type": "type_error.enum"
}
]
}Error Handling Best Practices
Catch Specific Exceptions
from sniperoute.exceptions import (
ValidationError,
AuthenticationError,
NotFoundError,
ConflictError,
RateLimitError
)
try:
response = await client.create_intent(intent)
except ValidationError as e:
print(f"Validation error: {e.message}")
except ConflictError as e:
print(f"Duplicate intent_id: {e.message}")
except RateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after}s")Log Request IDs
Request IDs help with debugging and support:
try:
response = await client.create_intent(intent)
except SnipeRouteAPIError as e:
logger.error(
f"API error: {e.message}",
extra={
"status_code": e.status_code,
"error_code": e.error_code,
"request_id": e.request_id # Include for support
}
)Implement Retry Logic
Retry transient errors (5xx, rate limits):
async def submit_with_retry(client, intent):
retryable_codes = [429, 500, 502, 503, 504]
for attempt in range(3):
try:
return await client.create_intent(intent)
except SnipeRouteAPIError as e:
if e.status_code in retryable_codes:
wait = 2 ** attempt
await asyncio.sleep(wait)
else:
raise # Don't retry client errorsValidate Before Submitting
Catch validation errors early:
def validate_intent(intent: TradeIntentRequest):
if intent.order_type == OrderType.LIMIT and not intent.limit_price:
raise ValueError("limit_price required for limit orders")
if intent.quantity <= 0:
raise ValueError("quantity must be > 0")
# Validate before API call
validate_intent(intent)
response = await client.create_intent(intent)Getting Help
If you encounter an error you can't resolve:
- Check the error message and
error_code - Review this documentation
- Check the Guides for common solutions
- Contact support@sniperoute.io with the
request_id