All API errors follow a consistent JSON structure:
{
"detail": "Error message describing what went wrong"
}
For some errors, additional context is provided:
{
"detail": {
"status": "shutting_down",
"timestamp": "2026-03-02T10:30:00.000Z",
"instance_id": "i-abc123xyz"
}
}
HTTP Status Codes
The Kortix API uses standard HTTP status codes to indicate success or failure.
2xx Success
Resource created successfully
4xx Client Errors
Invalid request format or parameters
Missing or invalid authentication credentials
Authenticated but lacking required permissions
Requested resource does not exist
Rate limit exceeded (currently 25 concurrent IPs per instance)
5xx Server Errors
500 Internal Server Error
Unexpected server error occurred
Service temporarily unavailable (maintenance, shutdown, or overload)
Authentication Errors
401 Unauthorized
Returned when authentication credentials are missing, invalid, or expired.
{
"detail": "No valid authentication credentials found"
}
Source: core/utils/auth_utils.py:136-492
Common Causes
- No Authentication Header: Missing both
X-API-Key and Authorization headers
- Wrong API Key Format: API key not in
pk_xxx:sk_xxx format
- Invalid Credentials: Wrong API key or JWT token
- Expired Token: JWT token past its
exp timestamp
- Token Forgery: Signature verification failed (possible attack)
Resolution
curl https://api.kortix.com/v1/agents \
-H "X-API-Key: pk_abc123:sk_xyz789"
403 Forbidden
Returned when credentials are valid but lack required permissions.
{
"detail": "Not authorized to access this thread"
}
Source: core/utils/auth_utils.py:143-146, 651-670, 963
Common Causes
- Wrong Account: Resource belongs to a different account
- Team Access: Not a member of the resource’s team
- Public vs Private: Attempting write access on read-only public resource
- Admin Only: Endpoint requires admin privileges
404 Not Found
Returned when a resource doesn’t exist or user lacks access to view it.
{
"detail": "Worker run not found"
}
Source: core/utils/auth_utils.py:319, 636, 895
For security, 404 responses don’t reveal whether the resource exists but user lacks access, or doesn’t exist at all.
Server Configuration Errors
500 Internal Server Error
Returned when server configuration is incorrect or an unexpected error occurs.
{
"detail": "Server authentication configuration error"
}
Source: core/utils/auth_utils.py:130-132, 222-225, 288-291, 680-684
503 Service Unavailable
Returned when the service is temporarily unavailable.
{
"detail": {
"status": "shutting_down",
"timestamp": "2026-03-02T10:30:00.000Z",
"instance_id": "i-abc123xyz"
}
}
Source: api.py:450-459, core/utils/auth_utils.py:548-549, 675-679
Common Causes
- Deployment: Kubernetes rolling update in progress
- Maintenance: Scheduled maintenance window
- Database Issues: Connection pool exhausted or shutdown
- Redis Issues: Cache unavailable (degraded mode)
Retry Strategy
For 503 errors, implement exponential backoff:
import time
import requests
def retry_request(url, max_retries=3, backoff=2):
for attempt in range(max_retries):
response = requests.get(url)
if response.status_code == 503:
wait_time = backoff ** attempt
time.sleep(wait_time)
continue
return response
raise Exception("Max retries exceeded")
API-Specific Errors
API Key Errors
{
"detail": "Invalid API key format. Expected format: pk_xxx:sk_xxx"
}
Source: core/services/api_keys.py:335-456
API key validation errors return generic messages to prevent enumeration attacks. Check server logs for detailed error information.
JWT Token Errors
{
"detail": "No valid authentication credentials found"
}
Source: core/utils/auth_utils.py:151-266
Thread Access Errors
{
"detail": "Thread not found"
}
Source: core/utils/auth_utils.py:591-684
Sandbox Access Errors
{
"detail": "Sandbox not found - no resource exists for this sandbox"
}
Source: core/utils/auth_utils.py:845-1112
Validation Errors
400 Bad Request
Returned when request data is malformed or violates validation rules.
{
"detail": [
{
"loc": ["body", "title"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
FastAPI automatically validates Pydantic models and returns detailed error information.
Debugging Errors
Enable Detailed Logging
In development, set log level to DEBUG:
Health Check Endpoints
Use health endpoints to diagnose issues:
curl https://api.kortix.com/v1/health
Source: api.py:444-546
Debug Response Example
{
"instance_id": "i-abc123xyz",
"active_runs_on_instance": 5,
"is_shutting_down": false,
"timestamp": "2026-03-02T10:30:00.000Z"
}
Source: api.py:498-508
Redis Health Response
{
"status": "healthy",
"latency_ms": 1.23,
"pool": {
"size": 10,
"in_use": 3
},
"timeouts": {
"default": 5000,
"streaming": 30000
},
"instance_id": "i-abc123xyz",
"timestamp": "2026-03-02T10:30:00.000Z"
}
Source: api.py:510-545
Common Debug Scenarios
- Check API key format:
pk_xxx:sk_xxx
- Verify key hasn’t expired or been revoked
- Confirm JWT token hasn’t expired
- Check JWT algorithm (ES256 or HS256)
- Ensure SUPABASE_JWT_SECRET is configured (HS256)
- Verify JWKS endpoint is reachable (ES256)
- Verify resource belongs to your account
- Check if you’re a team member
- Confirm resource isn’t private
- Check if write access is required
- Verify admin key for admin endpoints
- Confirm resource ID is correct
- Check if resource was deleted
- Verify you have access (404 may hide 403)
- Ensure correct account/project scope
- Check health endpoints
- Verify database connectivity
- Check Redis status
- Look for deployment in progress
- Review server logs (if accessible)
Error Handling Best Practices
Check Status Code
Always check the HTTP status code first to categorize the error
Parse Error Detail
Extract the detail field from the response body
Implement Retry Logic
For 5xx errors, retry with exponential backoff
Log for Debugging
Log all errors with request context for troubleshooting
User-Friendly Messages
Convert technical errors to user-friendly messages in your UI
Example Error Handler
import requests
import time
def handle_api_error(response):
"""Handle API errors with proper retry logic"""
if response.status_code == 401:
# Authentication error - refresh token or re-authenticate
raise AuthenticationError("Please log in again")
elif response.status_code == 403:
# Permission error - show access denied message
raise PermissionError("You don't have access to this resource")
elif response.status_code == 404:
# Not found - resource may not exist or no access
raise NotFoundError("Resource not found")
elif response.status_code == 429:
# Rate limit - wait and retry
retry_after = int(response.headers.get('Retry-After', 60))
time.sleep(retry_after)
# Retry request...
elif response.status_code == 503:
# Service unavailable - retry with backoff
for attempt in range(3):
time.sleep(2 ** attempt)
# Retry request...
elif response.status_code >= 500:
# Server error - log and show generic message
error_detail = response.json().get('detail', 'Unknown error')
logger.error(f"Server error: {error_detail}")
raise ServerError("Something went wrong. Please try again later.")
Next Steps
Authentication
Learn about authentication methods
API Introduction
Return to API overview