Error Handling
All GridBank API responses use standard HTTP status codes. Non-2xx responses include a JSON error envelope.
Error Response Format
Standard Error (4xx, 5xx)
json
{
"detail": "Human-readable error message"
}
Validation Error (422)
json
{
"detail": [
{
"loc": ["query", "per_page"],
"msg": "Input should be less than or equal to 80",
"type": "less_than_equal"
}
]
}
HTTP Status Codes
| Code | Name | Meaning | Action |
|---|---|---|---|
| 400 | Bad Request | Malformed request or invalid parameters | Fix request, retry |
| 401 | Unauthorized | Missing or invalid Bearer token | Verify API key, regenerate if needed |
| 403 | Forbidden | No active subscription for this operation | Upgrade subscription plan |
| 404 | Not Found | Video ID or resource does not exist | Check resource ID, search first |
| 422 | Validation Error | Invalid input data (see detail array) | Review field errors, fix input |
| 429 | Too Many Requests | Rate limit exceeded | Wait and retry (see Retry-After header) |
| 500 | Internal Server Error | Server-side error (temporary) | Retry after delay |
Common Errors
401 Unauthorized
Cause: Missing or invalid Bearer token
Solution:
- Verify Authorization: Bearer header is present in all requests
- Confirm API key is correct and not expired
- Regenerate key if compromised
```python from gridbank_api import GridbankClient, GridbankAPIError
client = GridbankClient(api_key="invalid_key") try: results = client.search_videos(q="test") except GridbankAPIError as e: if e.code == "unauthorized": print("API key is invalid. Check your credentials.") ```
javascript
const client = new GridbankClient({ apiKey: 'invalid_key' });
try {
await client.searchVideos({ q: 'test' });
} catch (error) {
if (error.code === 'unauthorized') {
console.error('API key is invalid.');
}
}
403 Forbidden
Cause: Account lacks subscription for this operation
Solution: - Upgrade to a plan that includes video downloads - Verify subscription is active (check usage_summary()) - Contact sales@gridbank.io if you believe this is an error
python
try:
download = client.download_video(video_id="video_abc123")
except GridbankAPIError as e:
if e.code == "forbidden":
print("You need an active subscription to download videos.")
usage = client.usage_summary()
print(f"Current tier: {usage.tier}")
javascript
try {
const download = await client.downloadVideo('video_abc123');
} catch (error) {
if (error.code === 'forbidden') {
console.error('You need an active subscription to download videos.');
const usage = await client.usageSummary();
console.log(`Current tier: ${usage.tier}`);
}
}
404 Not Found
Cause: Video ID does not exist
Solution: - Use search_videos() first to find valid video IDs - Confirm video ID format (alphanumeric, hyphens, underscores) - Check if video has been removed from library
python
try:
video = client.get_video(video_id="invalid_id")
except GridbankAPIError as e:
if e.code == "not_found":
print("Video not found. Search for videos first:")
results = client.search_videos(q="nature")
javascript
try {
const video = await client.getVideo('invalid_id');
} catch (error) {
if (error.code === 'not_found') {
console.error('Video not found. Searching instead:');
const results = await client.searchVideos({ q: 'nature' });
}
}
422 Validation Error
Cause: Invalid input data (e.g., per_page > 80)
Solution:
- Review the detail array for which field failed
- Adjust parameter values to match constraints
- Common issues:
- per_page must be 1–80
- page must be > 0
- q must be 1–200 characters
- expires_in must be 1–5 minutes
python
try:
results = client.search_videos(q="test", per_page=200)
except GridbankAPIError as e:
if e.code == "validation_error":
for error in e.details:
print(f"Field {error['loc']}: {error['msg']}")
javascript
try {
const results = await client.searchVideos({ q: 'test', perPage: 200 });
} catch (error) {
if (error.code === 'validation_error') {
error.details.forEach(err => {
console.error(`Field ${err.loc.join('.')}: ${err.msg}`);
});
}
}
429 Rate Limited
Cause: Too many requests in a short period
Solution:
- Respect the Retry-After response header
- Implement exponential backoff (1s, 2s, 4s, 8s...)
- Reduce request frequency
- Upgrade to higher tier for increased limits
```python import time from gridbank_api import GridbankAPIError
max_retries = 3 for attempt in range(max_retries): try: results = client.search_videos(q="test") break except GridbankAPIError as e: if e.code == "rate_limited": wait_time = (2 ** attempt) # exponential backoff print(f"Rate limited. Retrying in {wait_time}s...") time.sleep(wait_time) else: raise ```
javascript
async function searchWithRetry(query, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await client.searchVideos({ q: query });
} catch (error) {
if (error.code === 'rate_limited') {
const waitTime = Math.pow(2, attempt) * 1000;
console.log(`Rate limited. Retrying in ${waitTime}ms...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
} else {
throw error;
}
}
}
}
500 Internal Server Error
Cause: Temporary server-side issue
Solution: - Retry the request after a short delay - Check gridbank.io for incidents - Contact hello@gridbank.io if errors persist
Error Class Reference
Python
python
class GridbankAPIError(Exception):
code: str # Error code (e.g., "unauthorized")
message: str # Human-readable message
details: Any # Optional field-level details
status_code: int # HTTP status code
JavaScript
typescript
class GridbankAPIError extends Error {
code: string; // Error code
message: string; // Human-readable message
details: any; // Optional field-level details
statusCode: number; // HTTP status code
}
Support
Need help? Contact hello@gridbank.io with: - Error code and message - API key prefix (apik_xxxx) - Request details (endpoint, parameters) - Timestamp of error