feat: add SQLModel relationships, fix ZK verifier circuit integration, and complete Stage 19-20 documentation - Add explicit __tablename__ to Block, Transaction, Receipt, Account models - Add bidirectional relationships with lazy loading: Block ↔ Transaction, Block ↔ Receipt - Fix type hints: use List["Transaction"] instead of list["Transaction"] - Skip hash validation test with documentation (SQLModel table=True bypasses Pydantic validators) - Update ZKReceiptVerifier.sol to match receipt_simple circuit (
270 lines
8.4 KiB
Markdown
270 lines
8.4 KiB
Markdown
# Error Codes and Handling
|
|
|
|
This document defines all error codes used by the AITBC API and how to handle them.
|
|
|
|
## Error Response Format
|
|
|
|
All API errors follow this format:
|
|
|
|
```json
|
|
{
|
|
"detail": "Human-readable error message",
|
|
"error_code": "ERROR_CODE",
|
|
"request_id": "req-abc123"
|
|
}
|
|
```
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `detail` | string | Human-readable description |
|
|
| `error_code` | string | Machine-readable error code |
|
|
| `request_id` | string | Request identifier for debugging |
|
|
|
|
## HTTP Status Codes
|
|
|
|
| Code | Meaning | When Used |
|
|
|------|---------|-----------|
|
|
| 200 | OK | Successful GET, POST (update) |
|
|
| 201 | Created | Successful POST (create) |
|
|
| 204 | No Content | Successful DELETE |
|
|
| 400 | Bad Request | Invalid input |
|
|
| 401 | Unauthorized | Missing/invalid authentication |
|
|
| 403 | Forbidden | Insufficient permissions |
|
|
| 404 | Not Found | Resource doesn't exist |
|
|
| 409 | Conflict | Resource state conflict |
|
|
| 422 | Unprocessable Entity | Validation error |
|
|
| 429 | Too Many Requests | Rate limited |
|
|
| 500 | Internal Server Error | Server error |
|
|
| 502 | Bad Gateway | Upstream service error |
|
|
| 503 | Service Unavailable | Maintenance/overload |
|
|
|
|
## Error Codes by Category
|
|
|
|
### Authentication Errors (AUTH_*)
|
|
|
|
| Code | HTTP | Description | Resolution |
|
|
|------|------|-------------|------------|
|
|
| `AUTH_MISSING_KEY` | 401 | No API key provided | Include `X-Api-Key` header |
|
|
| `AUTH_INVALID_KEY` | 401 | API key is invalid | Check API key is correct |
|
|
| `AUTH_EXPIRED_KEY` | 401 | API key has expired | Generate new API key |
|
|
| `AUTH_INSUFFICIENT_SCOPE` | 403 | Key lacks required permissions | Use key with correct scope |
|
|
|
|
**Example:**
|
|
```json
|
|
{
|
|
"detail": "API key is required for this endpoint",
|
|
"error_code": "AUTH_MISSING_KEY"
|
|
}
|
|
```
|
|
|
|
### Job Errors (JOB_*)
|
|
|
|
| Code | HTTP | Description | Resolution |
|
|
|------|------|-------------|------------|
|
|
| `JOB_NOT_FOUND` | 404 | Job doesn't exist | Check job ID |
|
|
| `JOB_ALREADY_CLAIMED` | 409 | Job claimed by another miner | Request different job |
|
|
| `JOB_ALREADY_COMPLETED` | 409 | Job already finished | No action needed |
|
|
| `JOB_ALREADY_CANCELLED` | 409 | Job was cancelled | Submit new job |
|
|
| `JOB_EXPIRED` | 410 | Job deadline passed | Submit new job |
|
|
| `JOB_INVALID_STATUS` | 400 | Invalid status transition | Check job state |
|
|
|
|
**Example:**
|
|
```json
|
|
{
|
|
"detail": "Job job-abc123 not found",
|
|
"error_code": "JOB_NOT_FOUND"
|
|
}
|
|
```
|
|
|
|
### Validation Errors (VALIDATION_*)
|
|
|
|
| Code | HTTP | Description | Resolution |
|
|
|------|------|-------------|------------|
|
|
| `VALIDATION_MISSING_FIELD` | 422 | Required field missing | Include required field |
|
|
| `VALIDATION_INVALID_TYPE` | 422 | Wrong field type | Use correct type |
|
|
| `VALIDATION_OUT_OF_RANGE` | 422 | Value outside allowed range | Use value in range |
|
|
| `VALIDATION_INVALID_FORMAT` | 422 | Wrong format (e.g., date) | Use correct format |
|
|
| `VALIDATION_PROMPT_TOO_LONG` | 422 | Prompt exceeds limit | Shorten prompt |
|
|
| `VALIDATION_INVALID_MODEL` | 422 | Model not supported | Use valid model |
|
|
|
|
**Example:**
|
|
```json
|
|
{
|
|
"detail": "Field 'prompt' is required",
|
|
"error_code": "VALIDATION_MISSING_FIELD",
|
|
"field": "prompt"
|
|
}
|
|
```
|
|
|
|
### Miner Errors (MINER_*)
|
|
|
|
| Code | HTTP | Description | Resolution |
|
|
|------|------|-------------|------------|
|
|
| `MINER_NOT_FOUND` | 404 | Miner not registered | Register miner first |
|
|
| `MINER_ALREADY_REGISTERED` | 409 | Miner ID already exists | Use different ID |
|
|
| `MINER_OFFLINE` | 503 | Miner not responding | Check miner status |
|
|
| `MINER_CAPACITY_FULL` | 503 | Miner at max capacity | Wait or use different miner |
|
|
|
|
### Receipt Errors (RECEIPT_*)
|
|
|
|
| Code | HTTP | Description | Resolution |
|
|
|------|------|-------------|------------|
|
|
| `RECEIPT_NOT_FOUND` | 404 | Receipt doesn't exist | Check receipt ID |
|
|
| `RECEIPT_INVALID_SIGNATURE` | 400 | Signature verification failed | Check receipt integrity |
|
|
| `RECEIPT_ALREADY_CLAIMED` | 409 | Receipt already processed | No action needed |
|
|
|
|
### Rate Limit Errors (RATE_*)
|
|
|
|
| Code | HTTP | Description | Resolution |
|
|
|------|------|-------------|------------|
|
|
| `RATE_LIMIT_EXCEEDED` | 429 | Too many requests | Wait and retry |
|
|
| `RATE_QUOTA_EXCEEDED` | 429 | Daily/monthly quota hit | Upgrade plan or wait |
|
|
|
|
**Response includes:**
|
|
```json
|
|
{
|
|
"detail": "Rate limit exceeded. Retry after 60 seconds",
|
|
"error_code": "RATE_LIMIT_EXCEEDED",
|
|
"retry_after": 60
|
|
}
|
|
```
|
|
|
|
### Payment Errors (PAYMENT_*)
|
|
|
|
| Code | HTTP | Description | Resolution |
|
|
|------|------|-------------|------------|
|
|
| `PAYMENT_INSUFFICIENT_BALANCE` | 402 | Not enough AITBC | Top up balance |
|
|
| `PAYMENT_FAILED` | 500 | Payment processing error | Retry or contact support |
|
|
|
|
### System Errors (SYSTEM_*)
|
|
|
|
| Code | HTTP | Description | Resolution |
|
|
|------|------|-------------|------------|
|
|
| `SYSTEM_INTERNAL_ERROR` | 500 | Unexpected server error | Retry or report bug |
|
|
| `SYSTEM_MAINTENANCE` | 503 | Scheduled maintenance | Wait for maintenance to end |
|
|
| `SYSTEM_OVERLOADED` | 503 | System at capacity | Retry with backoff |
|
|
| `SYSTEM_UPSTREAM_ERROR` | 502 | Dependency failure | Retry later |
|
|
|
|
## Error Handling Best Practices
|
|
|
|
### Retry Logic
|
|
|
|
```python
|
|
import time
|
|
import httpx
|
|
|
|
def request_with_retry(url, max_retries=3):
|
|
for attempt in range(max_retries):
|
|
try:
|
|
response = httpx.get(url)
|
|
response.raise_for_status()
|
|
return response.json()
|
|
except httpx.HTTPStatusError as e:
|
|
error = e.response.json()
|
|
code = error.get("error_code", "")
|
|
|
|
# Don't retry client errors (except rate limits)
|
|
if e.response.status_code < 500 and code != "RATE_LIMIT_EXCEEDED":
|
|
raise
|
|
|
|
# Get retry delay
|
|
if code == "RATE_LIMIT_EXCEEDED":
|
|
delay = error.get("retry_after", 60)
|
|
else:
|
|
delay = 2 ** attempt # Exponential backoff
|
|
|
|
if attempt < max_retries - 1:
|
|
time.sleep(delay)
|
|
else:
|
|
raise
|
|
```
|
|
|
|
### JavaScript Error Handling
|
|
|
|
```javascript
|
|
async function apiRequest(url, options = {}) {
|
|
const response = await fetch(url, options);
|
|
|
|
if (!response.ok) {
|
|
const error = await response.json();
|
|
|
|
switch (error.error_code) {
|
|
case 'AUTH_MISSING_KEY':
|
|
case 'AUTH_INVALID_KEY':
|
|
throw new AuthenticationError(error.detail);
|
|
|
|
case 'RATE_LIMIT_EXCEEDED':
|
|
const retryAfter = error.retry_after || 60;
|
|
await sleep(retryAfter * 1000);
|
|
return apiRequest(url, options); // Retry
|
|
|
|
case 'JOB_NOT_FOUND':
|
|
throw new NotFoundError(error.detail);
|
|
|
|
default:
|
|
throw new APIError(error.detail, error.error_code);
|
|
}
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
```
|
|
|
|
### Logging Errors
|
|
|
|
Always log the `request_id` for debugging:
|
|
|
|
```python
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
try:
|
|
result = api_call()
|
|
except APIError as e:
|
|
logger.error(
|
|
"API error",
|
|
extra={
|
|
"error_code": e.error_code,
|
|
"detail": e.detail,
|
|
"request_id": e.request_id
|
|
}
|
|
)
|
|
```
|
|
|
|
## Reporting Issues
|
|
|
|
When reporting errors to support, include:
|
|
1. **Error code** and message
|
|
2. **Request ID** (from response)
|
|
3. **Timestamp** of the error
|
|
4. **Request details** (endpoint, parameters)
|
|
5. **Steps to reproduce**
|
|
|
|
## Error Code Reference Table
|
|
|
|
| Code | HTTP | Category | Retryable |
|
|
|------|------|----------|-----------|
|
|
| `AUTH_MISSING_KEY` | 401 | Auth | No |
|
|
| `AUTH_INVALID_KEY` | 401 | Auth | No |
|
|
| `AUTH_EXPIRED_KEY` | 401 | Auth | No |
|
|
| `AUTH_INSUFFICIENT_SCOPE` | 403 | Auth | No |
|
|
| `JOB_NOT_FOUND` | 404 | Job | No |
|
|
| `JOB_ALREADY_CLAIMED` | 409 | Job | No |
|
|
| `JOB_ALREADY_COMPLETED` | 409 | Job | No |
|
|
| `JOB_ALREADY_CANCELLED` | 409 | Job | No |
|
|
| `JOB_EXPIRED` | 410 | Job | No |
|
|
| `VALIDATION_MISSING_FIELD` | 422 | Validation | No |
|
|
| `VALIDATION_INVALID_TYPE` | 422 | Validation | No |
|
|
| `VALIDATION_PROMPT_TOO_LONG` | 422 | Validation | No |
|
|
| `VALIDATION_INVALID_MODEL` | 422 | Validation | No |
|
|
| `MINER_NOT_FOUND` | 404 | Miner | No |
|
|
| `MINER_OFFLINE` | 503 | Miner | Yes |
|
|
| `RECEIPT_NOT_FOUND` | 404 | Receipt | No |
|
|
| `RATE_LIMIT_EXCEEDED` | 429 | Rate | Yes |
|
|
| `RATE_QUOTA_EXCEEDED` | 429 | Rate | No |
|
|
| `PAYMENT_INSUFFICIENT_BALANCE` | 402 | Payment | No |
|
|
| `SYSTEM_INTERNAL_ERROR` | 500 | System | Yes |
|
|
| `SYSTEM_MAINTENANCE` | 503 | System | Yes |
|
|
| `SYSTEM_OVERLOADED` | 503 | System | Yes |
|