Error Handling
How the Volcano API reports errors, with status codes and JSON error bodies.
Error Response Format
All errors return JSON:
{
"error": "descriptive error message"
}HTTP Status Codes
2xx Success:
200 OK- Request succeeded201 Created- Resource created204 No Content- Success (no response body)
4xx Client Errors:
400 Bad Request- Invalid input or validation failed401 Unauthorized- Missing, invalid, or expired token403 Forbidden- Valid token but no permission404 Not Found- Resource doesn't exist409 Conflict- Resource state conflicts with the request (for example, a duplicate resource or deletion already in progress)429 Too Many Requests- Rate limit exceeded
5xx Server Errors:
500 Internal Server Error- Server-side error503 Service Unavailable- Function still provisioning
Common Errors
Authentication Errors
401 - Missing Token:
{"error": "authorization header required"}401 - Invalid Token:
{"error": "invalid token"}401 - Expired Token:
{"error": "invalid or expired token"}403 - Wrong Project:
{"error": "token does not have access to this project"}403 - Account Banned:
{"error": "account is banned"}Anon Key Errors
401 - Missing Anon Key:
{"error": "anon key required"}401 - Invalid Authorization Header:
{"error": "invalid authorization header"}401 - Invalid/Tampered Anon Key:
{"error": "invalid anon key"}401 - Wrong Project:
{"error": "anon key does not match project"}401 - Revoked (old key after regeneration):
{"error": "anon key has been revoked"}This occurs when using an old anon key JWT after the key has been regenerated. The key ID still exists but the JWT value no longer matches.
401 - Not Found in Database:
{"error": "anon key not found"}403 - Missing Permission:
{"error": "anon key does not have auth.signup permission"}403 - CORS Blocked:
{"error": "origin not allowed by CORS policy"}Rate Limiting
429 - Rate Limited:
{"error": "rate limit exceeded, try again later"}Headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1704128400Validation Errors
400 - Invalid Email:
{"error": "invalid email format"}400 - Weak Password:
{"error": "password must be at least 15 characters"}400 - Missing Field:
{"error": "name is required"}Resource Errors
404 - Not Found:
{"error": "project not found"}409 - Duplicate:
{"error": "user with this email already exists"}409 - Deletion in progress:
{"error": "frontend deletion already pending"}Deployments are serialized per resource and coalesced using latest-wins
queueing. A deploy returns 409 only after deletion has been requested; wait
for deletion to finish before creating the resource again.
503 - Still Provisioning:
{"error": "function is still provisioning, please try again in a few seconds"}Error Handling
JavaScript/TypeScript
try {
const response = await fetch('https://api.volcano.dev/projects', {
headers: { 'Authorization': `Bearer ${token}` }
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error);
}
const data = await response.json();
return data;
} catch (error) {
console.error('API Error:', error.message);
// Handle error
}With Volcano SDK
try {
await volcano.auth.signIn({...});
} catch (error) {
if (error.message.includes('rate limit')) {
// Show rate limit message
} else if (error.message.includes('invalid')) {
// Show invalid credentials
}
}Retry Logic
async function apiCallWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url, options);
if (response.status === 429) {
// Rate limited - wait and retry
const resetTime = response.headers.get('X-RateLimit-Reset');
await sleep(calculateWaitTime(resetTime));
continue;
}
if (response.status === 503) {
// Still provisioning - wait and retry
await sleep(2000);
continue;
}
return response;
} catch (error) {
if (i === maxRetries - 1) throw error;
await sleep(1000 * (i + 1));
}
}
}See Also
- Authentication - Auth headers and tokens