# Common Error Codes

Reference for Clore.ai API error codes and how to handle them.

## Response Code Structure

Every API response includes a `code` field:

```json
{
  "code": 0,
  "data": {...}
}
```

```json
{
  "code": 6,
  "error": "not_enough_balance"
}
```

## Error Codes

| Code | Meaning                 | HTTP Status |
| ---- | ----------------------- | ----------- |
| 0    | Success                 | 200         |
| 1    | Database error          | 500         |
| 2    | Invalid input           | 400         |
| 3    | Invalid/missing API key | 401         |
| 4    | Invalid endpoint        | 404         |
| 5    | Rate limit exceeded     | 429         |
| 6    | See error field         | varies      |

## Common Error Messages (Code 6)

### Order Creation Errors

| Error                         | Meaning                        | Solution                        |
| ----------------------------- | ------------------------------ | ------------------------------- |
| `server-dont-exist`           | Server ID not found            | Check marketplace for valid IDs |
| `server-offline`              | Server is offline              | Choose different server         |
| `server-already-rented`       | Server has active rental       | Wait or choose another          |
| `not_enough_balance`          | Insufficient funds             | Top up wallet                   |
| `cant_rent_from_yourself`     | Can't rent own server          | Use different account           |
| `too_low_price`               | Spot bid below minimum         | Increase bid price              |
| `you_already_have_spot_order` | Duplicate spot order           | Cancel existing first           |
| `currency-not-allowed`        | Server doesn't accept currency | Use different currency          |
| `machine-is-on-gigaspot`      | Server in gigaspot mode        | Use gigaspot API                |

### Order Management Errors

| Error                        | Meaning                 | Solution            |
| ---------------------------- | ----------------------- | ------------------- |
| `you_dont_own_this_order`    | Order not yours         | Check order ID      |
| `order_not_active`           | Order already ended     | No action needed    |
| `issue_description_too_long` | Issue text > 2048 chars | Shorten description |

### Spot Price Errors

| Error                         | Meaning                  | Solution              |
| ----------------------------- | ------------------------ | --------------------- |
| `order_dont_exist`            | Order not found          | Verify order ID       |
| `amount_too_low`              | Price below minimum      | Increase price        |
| `can_lower_every_600_seconds` | Rate limited             | Wait before lowering  |
| `exceeded_max_step`           | Price decrease too large | Use smaller decrement |

### Server Settings Errors

| Error                        | Meaning                     | Solution               |
| ---------------------------- | --------------------------- | ---------------------- |
| `server_dont_exist`          | Server not found            | Check server name      |
| `not_all_parameters_present` | Missing required fields     | Check documentation    |
| `invalid_mrl`                | Invalid max rental length   | Use valid range        |
| `invalid_input`              | Parameter validation failed | Check parameter values |

## Handling Errors in Python

```python
import requests
import time
from typing import Optional

class CloreAPIError(Exception):
    def __init__(self, code: int, message: str, response: dict):
        self.code = code
        self.message = message
        self.response = response
        super().__init__(f"[{code}] {message}")

class RateLimitError(CloreAPIError):
    pass

class InsufficientBalanceError(CloreAPIError):
    pass

class ServerNotAvailableError(CloreAPIError):
    pass

def handle_clore_response(response: dict) -> dict:
    """Handle Clore API response with proper error typing."""
    code = response.get("code", -1)
    
    if code == 0:
        return response
    
    error = response.get("error", "Unknown error")
    
    # Map error codes to exceptions
    if code == 5:
        raise RateLimitError(code, "Rate limit exceeded", response)
    
    if code == 3:
        raise CloreAPIError(code, "Invalid or missing API key", response)
    
    if code == 6:
        # Handle specific error messages
        if "not_enough_balance" in str(error):
            raise InsufficientBalanceError(code, error, response)
        
        if "server-already-rented" in str(error) or "server-offline" in str(error):
            raise ServerNotAvailableError(code, error, response)
    
    raise CloreAPIError(code, error, response)

def clore_request_with_retry(
    method: str, 
    url: str, 
    headers: dict,
    max_retries: int = 3,
    **kwargs
) -> dict:
    """Make Clore API request with retry logic."""
    
    for attempt in range(max_retries):
        try:
            response = requests.request(method, url, headers=headers, **kwargs)
            data = response.json()
            return handle_clore_response(data)
            
        except RateLimitError:
            # Exponential backoff
            wait_time = 2 ** attempt
            print(f"Rate limited, waiting {wait_time}s...")
            time.sleep(wait_time)
            
        except InsufficientBalanceError as e:
            # Don't retry - need user action
            raise e
            
        except ServerNotAvailableError as e:
            # Don't retry - need different server
            raise e
            
        except CloreAPIError as e:
            if attempt == max_retries - 1:
                raise e
            time.sleep(1)
    
    raise Exception("Max retries exceeded")

# Usage example
try:
    result = clore_request_with_retry(
        "POST", 
        "https://api.clore.ai/v1/create_order",
        headers={"auth": "YOUR_API_KEY"},
        json={...}
    )
except InsufficientBalanceError:
    print("Please top up your wallet")
except ServerNotAvailableError:
    print("Server not available, trying another...")
except RateLimitError:
    print("API rate limit - slow down requests")
except CloreAPIError as e:
    print(f"API error: {e}")
```

## Rate Limit Handling

The API allows **1 request per second**. Implement proper rate limiting:

```python
import time
from functools import wraps

class RateLimiter:
    def __init__(self, min_interval: float = 1.1):
        self.min_interval = min_interval
        self.last_request = 0
    
    def wait(self):
        elapsed = time.time() - self.last_request
        if elapsed < self.min_interval:
            time.sleep(self.min_interval - elapsed)
        self.last_request = time.time()

# Usage
rate_limiter = RateLimiter()

def make_request():
    rate_limiter.wait()
    # ... make request
```

## Debugging Tips

1. **Check the `error` field** - Code 6 always includes an `error` field with details
2. **Validate input** - Code 2 means your request data is malformed
3. **Check API key** - Code 3 means authentication failed
4. **Slow down** - Code 5 means you're hitting rate limits
5. **Check server status** - Some errors indicate server-side issues (try again later)

## See Also

* [API Quick Reference](https://docs.clore.ai/dev/reference/api-reference)
* [Getting Started](https://docs.clore.ai/dev/getting-started/quick-start)
