Skip to main content

Error Codes Reference

ZhenRent uses conventional HTTP status codes and standardized error responses.

Error Response Format

All errors follow this structure:

{
"error": {
"code": "error_code_here",
"message": "Human-readable error description",
"details": {} // Optional: Additional context
}
}

HTTP Status Codes

Status CodeMeaningWhen It Occurs
400Bad RequestInvalid request parameters
401UnauthorizedMissing or invalid API key
402Payment RequiredInsufficient balance
403ForbiddenInsufficient permissions
404Not FoundResource doesn't exist
429Too Many RequestsRate limit exceeded
500Internal Server ErrorPlatform error
503Service UnavailableService temporarily down

Error Code Categories

Authentication Errors (401, 403)

invalid_api_key

Status: 401 Unauthorized

Cause: API key is invalid, expired, or revoked

Response:

{
"error": {
"code": "invalid_api_key",
"message": "Invalid or expired API key"
}
}

Solution:

  • Verify API key format starts with zr_live_ or zr_test_
  • Check Authorization header: Bearer YOUR_KEY
  • Confirm key hasn't been deleted in dashboard
  • Create new API key if necessary

authentication_required

Status: 401 Unauthorized

Cause: Missing Authorization header

Response:

{
"error": {
"code": "authentication_required",
"message": "Authentication required. Please provide API key in Authorization header."
}
}

Solution:

headers = {
"Authorization": f"Bearer {API_KEY}"
}

insufficient_permissions

Status: 403 Forbidden

Cause: API key lacks required permissions

Response:

{
"error": {
"code": "insufficient_permissions",
"message": "API key does not have permission to perform this action",
"required_permission": "task:create"
}
}

Solution: Add required permission to API key in dashboard

Payment Errors (402)

insufficient_balance

Status: 402 Payment Required

Cause: Account balance too low to create task

Response:

{
"error": {
"code": "insufficient_balance",
"message": "Account balance (3000 cents) insufficient for task cost (5000 cents)",
"balance_cents": 3000,
"required_cents": 5000
}
}

Solution:

  1. Check current balance: GET /api/v1/payment/balance
  2. Recharge account via dashboard
  3. Retry task creation

Validation Errors (400)

validation_error

Status: 400 Bad Request

Cause: One or more request parameters are invalid

Response:

{
"error": {
"code": "validation_error",
"message": "Request validation failed",
"details": [
{
"type": "greater_than_equal",
"loc": ["body", "budget_cents"],
"msg": "Input should be greater than or equal to 1000",
"input": 500
},
{
"type": "future_date",
"loc": ["body", "deadline_at"],
"msg": "Deadline must be in the future",
"input": "2023-01-01T00:00:00Z"
}
]
}
}

Common validation issues:

FieldIssueSolution
budget_cents< 1000Use at least 1000 (10 RMB)
deadline_atPast dateUse future ISO 8601 date
latitudeOut of rangeUse -90 to 90
longitudeOut of rangeUse -180 to 180
titleToo longMax 200 characters
descriptionMissingRequired field

Solution: Fix parameter values based on details array

invalid_json

Status: 400 Bad Request

Cause: Malformed JSON in request body

Response:

{
"error": {
"code": "invalid_json",
"message": "Invalid JSON in request body",
"details": "Expecting ',' delimiter: line 5 column 3"
}
}

Solution: Validate JSON syntax before sending

Resource Errors (404)

task_not_found

Status: 404 Not Found

Cause: Task doesn't exist or not owned by your account

Response:

{
"error": {
"code": "task_not_found",
"message": "Task not found or you don't have access"
}
}

Solution:

  • Verify task ID is correct
  • Confirm you own the task
  • Check task wasn't deleted

result_not_available

Status: 404 Not Found

Cause: Attempted to retrieve result for incomplete task

Response:

{
"error": {
"code": "result_not_available",
"message": "Task is still in progress",
"current_status": "in_progress"
}
}

Solution: Wait until task status is completed

Rate Limit Errors (429)

rate_limit_exceeded

Status: 429 Too Many Requests

Cause: Exceeded API request rate limit

Response:

{
"error": {
"code": "rate_limit_exceeded",
"message": "Too many requests. Please retry after 60 seconds.",
"retry_after": 60
}
}

Headers:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1680261600
Retry-After: 60

Solution: Implement exponential backoff

import time

def api_request_with_backoff(func, max_retries=3):
for attempt in range(max_retries):
try:
return func()
except RateLimitError as e:
if attempt == max_retries - 1:
raise
wait_time = 2 ** attempt # 1s, 2s, 4s
time.sleep(wait_time)

Server Errors (500, 503)

internal_error

Status: 500 Internal Server Error

Cause: Unexpected server-side error

Response:

{
"error": {
"code": "internal_error",
"message": "An internal error occurred. Please try again.",
"request_id": "req_abc123"
}
}

Solution:

  1. Retry request (may be transient)
  2. If persists, contact support with request_id

service_unavailable

Status: 503 Service Unavailable

Cause: Service temporarily unavailable (maintenance or overload)

Response:

{
"error": {
"code": "service_unavailable",
"message": "Service temporarily unavailable. Please try again later.",
"retry_after": 300
}
}

Solution: Retry after specified seconds

Error Handling Best Practices

1. Always Check Status Code

response = requests.post(url, json=data, headers=headers)

if response.status_code == 201:
task = response.json()
print(f"Success: {task['task_id']}")
elif response.status_code == 402:
print("Insufficient balance. Please recharge.")
elif response.status_code &gt;= 500:
print("Server error. Please retry.")
else:
print(f"Error: {response.json()}")

2. Implement Retry Logic

import time
import requests
from requests.exceptions import RequestException

def api_call_with_retry(func, max_retries=3):
"""Retry API calls with exponential backoff"""
for attempt in range(max_retries):
try:
response = func()
response.raise_for_status()
return response.json()

except requests.HTTPError as e:
if e.response.status_code in [500, 502, 503, 504]:
# Retry server errors
if attempt < max_retries - 1:
wait_time = 2 ** attempt
time.sleep(wait_time)
continue
elif e.response.status_code == 429:
# Respect rate limit
retry_after = int(e.response.headers.get('Retry-After', 60))
time.sleep(retry_after)
continue
raise

except RequestException as e:
# Retry network errors
if attempt < max_retries - 1:
time.sleep(2 ** attempt)
continue
raise

raise Exception("Max retries exceeded")

# Usage
def make_request():
return requests.post(url, json=data, headers=headers)

try:
result = api_call_with_retry(make_request)
print(f"Success: {result}")
except Exception as e:
print(f"Failed after retries: {e}")

3. Parse Error Details

def handle_api_error(response):
"""Extract meaningful error information"""
error_data = response.json()['error']

code = error_data['code']
message = error_data['message']

if code == 'validation_error':
# Extract field-specific errors
for detail in error_data.get('details', []):
field = detail['loc'][-1]
msg = detail['msg']
print(f"Validation error on '{field}': {msg}")

elif code == 'insufficient_balance':
balance = error_data['balance_cents'] / 100
required = error_data['required_cents'] / 100
print(f"Insufficient balance: {balance} RMB (need {required} RMB)")

else:
print(f"Error [{code}]: {message}")

# Usage
response = requests.post(url, json=data, headers=headers)
if not response.ok:
handle_api_error(response)

4. Log Request IDs

import logging

def make_api_request(url, **kwargs):
response = requests.post(url, **kwargs)

request_id = response.headers.get('X-Request-ID')

if response.ok:
logging.info(f"Request succeeded: {request_id}")
else:
logging.error(
f"Request failed: {request_id}",
extra={
'status_code': response.status_code,
'error': response.json()
}
)

return response

5. Implement Circuit Breaker

from datetime import datetime, timedelta

class CircuitBreaker:
def __init__(self, failure_threshold=5, timeout=60):
self.failure_threshold = failure_threshold
self.timeout = timeout
self.failures = 0
self.last_failure_time = None
self.state = 'closed' # closed, open, half-open

def call(self, func):
if self.state == 'open':
if datetime.now() - self.last_failure_time > timedelta(seconds=self.timeout):
self.state = 'half-open'
else:
raise Exception("Circuit breaker is open")

try:
result = func()
self.on_success()
return result
except Exception as e:
self.on_failure()
raise

def on_success(self):
self.failures = 0
self.state = 'closed'

def on_failure(self):
self.failures += 1
self.last_failure_time = datetime.now()
if self.failures &gt;= self.failure_threshold:
self.state = 'open'

# Usage
breaker = CircuitBreaker()

try:
result = breaker.call(lambda: api_request())
except Exception as e:
print(f"Request failed: {e}")

Testing Error Scenarios

Test Validation Errors

# Test invalid budget
response = requests.post(url, json={
"budget_cents": 500, # Too low
# ... other fields
})
assert response.status_code == 400
assert response.json()['error']['code'] == 'validation_error'

Test Authentication Errors

# Test missing API key
response = requests.post(url, json=data) # No auth header
assert response.status_code == 401

# Test invalid API key
response = requests.post(url, json=data, headers={
"Authorization": "Bearer invalid_key"
})
assert response.status_code == 401

Test Rate Limiting

# Rapid requests to trigger rate limit
for i in range(150): # Exceed 100/min limit
response = requests.get(url, headers=headers)
if response.status_code == 429:
print(f"Rate limited after {i} requests")
break

Contact Support

If you encounter errors not documented here:

  • Email: support@zhenrent.com
  • Include:
    • Error code and message
    • Request ID (from X-Request-ID header)
    • Timestamp
    • Request details (sanitize sensitive data)

Response time: < 24 hours