Error Handling
This guide covers common HTTP status codes, error response formats, and best practices for handling errors across all WAYSCloud services.
Error Response Format
All WAYSCloud APIs return errors in a consistent JSON format:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error description",
"details": {
"field": "parameter_name",
"provided": "invalid_value",
"expected": "expected_format"
}
}
}
Fields:
code- Machine-readable error code (see below)message- Human-readable error descriptiondetails- Optional additional context about the error
HTTP Status Codes
400 Bad Request
The request was malformed or contains invalid parameters.
Example:
{
"error": {
"code": "INVALID_PARAMETER",
"message": "Invalid parameter value",
"details": {
"field": "ttl",
"provided": "-100",
"expected": "Positive integer (60-86400)"
}
}
}
Common Causes:
- Missing required parameters
- Invalid parameter format
- Parameter value out of range
- Malformed JSON
Resolution:
- Validate all parameters before sending
- Check API documentation for required fields
- Ensure JSON is properly formatted
401 Unauthorized
The API key is missing, invalid, or expired.
Example:
{
"error": {
"code": "AUTH_FAILED",
"message": "Invalid or expired API key"
}
}
Common Causes:
- Missing
Authorizationheader - Invalid API key format
- API key has been revoked
- Missing
Bearerprefix - Extra spaces in header
Resolution:
# Correct format
Authorization: Bearer wayscloud_storage_abc123_YourSecretKey
# Common mistakes:
# ❌ Authorization: wayscloud_storage_abc123_YourSecretKey
# ❌ Authorization: Bearer wayscloud_storage_abc123_YourSecretKey (extra spaces)
# ❌ Authorization: bearer wayscloud_storage_abc123_YourSecretKey (lowercase)
403 Forbidden
The API key doesn't have permission for the requested operation.
Example:
{
"error": {
"code": "INSUFFICIENT_PERMISSIONS",
"message": "API key does not have permission for this service"
}
}
Common Causes:
- Using wrong service key (e.g., storage key for LLM API)
- Key doesn't have required scope
- IP not whitelisted (if IP restrictions enabled)
Resolution:
- Create new API key with correct service permissions
- Check IP whitelist configuration
- Verify key scopes in dashboard
404 Not Found
The requested resource doesn't exist.
Example:
{
"error": {
"code": "RESOURCE_NOT_FOUND",
"message": "The requested resource was not found",
"details": {
"resource_type": "zone",
"resource_id": "zone_xyz123"
}
}
}
Common Causes:
- Incorrect resource ID
- Resource has been deleted
- Wrong endpoint URL
- Typo in resource name
Resolution:
- Verify resource exists using list/get operations
- Check for typos in IDs and URLs
- Ensure resource wasn't deleted
409 Conflict
The request conflicts with the current state of the resource.
Example:
{
"error": {
"code": "RESOURCE_ALREADY_EXISTS",
"message": "A resource with this name already exists",
"details": {
"resource_type": "database",
"name": "my_app_db"
}
}
}
Common Causes:
- Duplicate resource name
- Resource already in desired state
- Concurrent modification
Resolution:
- Use unique names for resources
- Check if resource already exists before creating
- Implement idempotent operations where possible
413 Request Entity Too Large
The request payload exceeds maximum allowed size.
Example:
{
"error": {
"code": "PAYLOAD_TOO_LARGE",
"message": "Request payload exceeds maximum allowed size",
"details": {
"max_size": "50GB",
"provided_size": "75GB"
}
}
}
Service Limits:
- Storage: 50GB per file
- LLM: 32K-200K tokens depending on model
- Database: 1TB per database
Resolution:
- Split large uploads using multipart upload (Storage)
- Reduce context size (LLM)
- Use chunked uploads for large files
429 Too Many Requests
Rate limit exceeded for your API key.
Example:
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded",
"retry_after": 60,
"details": {
"limit": "1000 requests/minute",
"current_usage": 1000
}
}
}
Resolution:
- Implement exponential backoff
- Check
Retry-Afterheader - Spread requests over time
- Consider upgrading plan for higher limits
See Rate Limits for detailed limits per service.
500 Internal Server Error
An unexpected error occurred on the server.
Example:
{
"error": {
"code": "INTERNAL_ERROR",
"message": "An internal server error occurred",
"request_id": "req_abc123xyz"
}
}
Resolution:
- Retry the request after a delay
- If error persists, contact support with
request_id - Check status page: https://status.wayscloud.services
503 Service Unavailable
The service is temporarily unavailable (maintenance or overload).
Example:
{
"error": {
"code": "SERVICE_UNAVAILABLE",
"message": "Service temporarily unavailable",
"retry_after": 300
}
}
Resolution:
- Wait and retry after
retry_afterseconds - Check status page for scheduled maintenance
- Implement retry logic with exponential backoff
507 Insufficient Storage
Storage quota exceeded (Storage API only).
Example:
{
"error": {
"code": "QUOTA_EXCEEDED",
"message": "Storage quota exceeded",
"details": {
"quota": "100GB",
"used": "100GB"
}
}
}
Resolution:
- Delete unused files
- Upgrade storage plan
- Check usage in dashboard
Service-Specific Error Codes
Storage API
| Code | Description | Resolution |
|---|---|---|
BUCKET_NOT_FOUND | Bucket doesn't exist | Verify bucket name |
OBJECT_NOT_FOUND | Object doesn't exist | Check object key |
BUCKET_ALREADY_EXISTS | Bucket name taken | Use different name |
INVALID_BUCKET_NAME | Invalid bucket name format | Use lowercase, numbers, hyphens only |
LLM API
| Code | Description | Resolution |
|---|---|---|
MODEL_NOT_FOUND | Invalid model name | Check available models |
CONTEXT_LENGTH_EXCEEDED | Input too long for model | Reduce input size or use model with larger context |
INVALID_MESSAGES | Messages format invalid | Follow OpenAI message format |
Database API
| Code | Description | Resolution |
|---|---|---|
DATABASE_NOT_FOUND | Database doesn't exist | Verify database name |
DATABASE_ALREADY_EXISTS | Database name taken | Use different name |
SNAPSHOT_NOT_FOUND | Snapshot doesn't exist | Check snapshot ID |
INVALID_DB_NAME | Invalid database name | Use alphanumeric and underscores only |
DNS API
| Code | Description | Resolution |
|---|---|---|
ZONE_NOT_FOUND | Zone doesn't exist | Verify zone ID |
RECORD_NOT_FOUND | Record doesn't exist | Check record ID |
INVALID_RECORD_TYPE | Unsupported record type | Use A, AAAA, CNAME, MX, TXT, SRV, CAA |
INVALID_VALUE | Record value format invalid | Check value format for record type |
DUPLICATE_RECORD | Record already exists | Update existing record |
DNSSEC_ERROR | DNSSEC validation failed | Check DS records at registrar |
GPU API
| Code | Description | Resolution |
|---|---|---|
JOB_NOT_FOUND | Job doesn't exist | Verify job ID |
INVALID_JOB_TYPE | Unsupported job type | Use video_generation, tts, or transcription |
CONTENT_MODERATION_FAILED | Content violates policy | Review content policy |
INSUFFICIENT_CREDITS | Not enough credits | Add credits to account |
Retry Strategies
Exponential Backoff
Implement exponential backoff for transient errors (429, 500, 503):
import time
import requests
def api_call_with_retry(url, headers, max_retries=5):
for attempt in range(max_retries):
try:
response = requests.get(url, headers=headers)
if response.status_code == 200:
return response.json()
# Retry on transient errors
if response.status_code in [429, 500, 503]:
retry_after = int(response.headers.get('Retry-After', 2 ** attempt))
print(f"Retry after {retry_after}s (attempt {attempt + 1}/{max_retries})")
time.sleep(retry_after)
continue
# Don't retry on client errors
if 400 <= response.status_code < 500:
response.raise_for_status()
except requests.exceptions.RequestException as e:
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt)
raise Exception("Max retries exceeded")
JavaScript/Node.js Example
async function apiCallWithRetry(url, headers, maxRetries = 5) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, { headers });
if (response.ok) {
return await response.json();
}
// Retry on transient errors
if ([429, 500, 503].includes(response.status)) {
const retryAfter = parseInt(response.headers.get('Retry-After') || Math.pow(2, attempt));
console.log(`Retry after ${retryAfter}s (attempt ${attempt + 1}/${maxRetries})`);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
continue;
}
// Don't retry client errors
if (response.status >= 400 && response.status < 500) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
} catch (error) {
if (attempt === maxRetries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
}
}
throw new Error('Max retries exceeded');
}
Best Practices
1. Always Handle Errors
# Bad - no error handling
response = requests.get(url, headers=headers)
data = response.json()
# Good - proper error handling
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
data = response.json()
except requests.exceptions.HTTPError as e:
print(f"HTTP error: {e.response.status_code}")
print(f"Error details: {e.response.json()}")
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
2. Log Request IDs
Always log the request_id from error responses for debugging:
try:
response = requests.post(url, json=data, headers=headers)
response.raise_for_status()
except requests.exceptions.HTTPError as e:
error_data = e.response.json()
request_id = error_data.get('request_id', 'N/A')
print(f"Error: {error_data['error']['message']}")
print(f"Request ID: {request_id}") # Include this when contacting support
3. Validate Before Sending
Validate parameters before making API calls:
def create_dns_record(zone_id, record_type, name, value, ttl):
# Validate parameters
if record_type not in ['A', 'AAAA', 'CNAME', 'MX', 'TXT']:
raise ValueError(f"Invalid record type: {record_type}")
if not (60 <= ttl <= 86400):
raise ValueError(f"TTL must be between 60 and 86400, got {ttl}")
# Make API call
return api_client.create_record(zone_id, record_type, name, value, ttl)
4. Use Timeouts
Always set reasonable timeouts:
# Bad - no timeout (can hang forever)
response = requests.get(url, headers=headers)
# Good - with timeout
response = requests.get(url, headers=headers, timeout=30)
5. Monitor Error Rates
Track error rates in your application:
import logging
from collections import Counter
error_counter = Counter()
def make_api_call(url, headers):
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
status = e.response.status_code
error_counter[status] += 1
# Alert if error rate is high
if error_counter[status] > 100:
logging.error(f"High error rate for status {status}: {error_counter[status]} errors")
raise
Getting Help
If you encounter persistent errors:
- Check the error code - See if it's documented above
- Review your request - Validate parameters and format
- Check service status - https://status.wayscloud.services
- Contact support - Include:
- Error code and message
- Request ID (if provided)
- Timestamp of error
- Endpoint and parameters used (sanitize sensitive data)
Support Channels:
- Email: support@wayscloud.no
- Documentation: https://docs.wayscloud.services
- Dashboard: https://my.wayscloud.services
Next Steps
- Rate Limits - Rate limits per service
- Authentication - API key authentication
- Troubleshooting - Service-specific troubleshooting