Error Codes
This page documents all error codes returned by the FireBackup API. Understanding these errors helps you handle failures gracefully and provide meaningful feedback to users.
Error Response Format
All API errors follow a consistent JSON format:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message",
"details": {
// Optional additional context
}
}
}
| Field | Type | Description |
|---|---|---|
success | boolean | Always false for errors |
error.code | string | Machine-readable error code |
error.message | string | Human-readable description |
error.details | object | Additional context (optional) |
HTTP Status Codes
| Status | Description | Common Causes |
|---|---|---|
400 | Bad Request | Invalid input, validation errors |
401 | Unauthorized | Missing or invalid token |
403 | Forbidden | Insufficient permissions |
404 | Not Found | Resource doesn't exist |
409 | Conflict | Duplicate resource, state conflict |
422 | Unprocessable Entity | Valid JSON but invalid semantics |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Server-side failure |
502 | Bad Gateway | Upstream service failure |
503 | Service Unavailable | Maintenance or overload |
Authentication Errors
UNAUTHORIZED
Status: 401
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication required"
}
}
Causes:
- Missing
Authorizationheader - Token not provided
Resolution: Include a valid Bearer token in the Authorization header.
INVALID_TOKEN
Status: 401
{
"success": false,
"error": {
"code": "INVALID_TOKEN",
"message": "Invalid or malformed token"
}
}
Causes:
- Malformed JWT
- Invalid signature
- Token from different issuer
Resolution: Obtain a new token through the authentication flow.
TOKEN_EXPIRED
Status: 401
{
"success": false,
"error": {
"code": "TOKEN_EXPIRED",
"message": "Token has expired",
"details": {
"expiredAt": "2024-01-15T10:00:00Z"
}
}
}
Causes:
- JWT past expiration time
- Session timeout
Resolution: Refresh the token or re-authenticate.
INVALID_REFRESH_TOKEN
Status: 401
{
"success": false,
"error": {
"code": "INVALID_REFRESH_TOKEN",
"message": "Invalid or expired refresh token"
}
}
Causes:
- Refresh token revoked
- Refresh token expired
- Token already used (one-time use)
Resolution: Re-authenticate through the full OAuth flow.
Authorization Errors
PERMISSION_DENIED
Status: 403
{
"success": false,
"error": {
"code": "PERMISSION_DENIED",
"message": "You don't have permission to perform this action",
"details": {
"requiredRole": "admin",
"currentRole": "member",
"requiredPermission": "backups:delete"
}
}
}
Causes:
- User role insufficient for operation
- Resource belongs to another organization
Resolution: Request elevated permissions from an admin.
ORGANIZATION_ACCESS_DENIED
Status: 403
{
"success": false,
"error": {
"code": "ORGANIZATION_ACCESS_DENIED",
"message": "You are not a member of this organization"
}
}
Causes:
- User not in organization
- Organization ID mismatch
- Membership revoked
Resolution: Verify organization membership or use correct organization ID.
MISSING_ORGANIZATION_HEADER
Status: 400
{
"success": false,
"error": {
"code": "MISSING_ORGANIZATION_HEADER",
"message": "X-Organization-Id header is required"
}
}
Causes:
- Header not provided
- Empty header value
Resolution: Include X-Organization-Id header with valid organization ID.
Resource Errors
PROJECT_NOT_FOUND
Status: 404
{
"success": false,
"error": {
"code": "PROJECT_NOT_FOUND",
"message": "Project with ID 'proj_xxx' not found"
}
}
Causes:
- Project doesn't exist
- Project deleted
- Wrong organization context
Resolution: Verify project ID and organization context.
BACKUP_NOT_FOUND
Status: 404
{
"success": false,
"error": {
"code": "BACKUP_NOT_FOUND",
"message": "Backup 'bkp_xxx' not found"
}
}
Causes:
- Backup doesn't exist
- Backup deleted
- Wrong project context
Resolution: Verify backup ID exists for the specified project.
SCHEDULE_NOT_FOUND
Status: 404
{
"success": false,
"error": {
"code": "SCHEDULE_NOT_FOUND",
"message": "Schedule 'sched_xxx' not found"
}
}
STORAGE_NOT_FOUND
Status: 404
{
"success": false,
"error": {
"code": "STORAGE_NOT_FOUND",
"message": "Storage destination not found"
}
}
WEBHOOK_NOT_FOUND
Status: 404
{
"success": false,
"error": {
"code": "WEBHOOK_NOT_FOUND",
"message": "Webhook not found"
}
}
ORGANIZATION_NOT_FOUND
Status: 404
{
"success": false,
"error": {
"code": "ORGANIZATION_NOT_FOUND",
"message": "Organization not found"
}
}
PITR_NOT_ENABLED
Status: 400
{
"success": false,
"error": {
"code": "PITR_NOT_ENABLED",
"message": "PITR is not enabled for this project"
}
}
Resolution: Enable PITR using the /pitr/enable endpoint.
Validation Errors
VALIDATION_ERROR
Status: 400
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": {
"errors": [
{
"field": "email",
"message": "Invalid email format"
},
{
"field": "name",
"message": "Name must be at least 2 characters"
}
]
}
}
}
Causes:
- Missing required fields
- Invalid field format
- Value out of range
Resolution: Check the details.errors array for specific field issues.
INVALID_CRON
Status: 400
{
"success": false,
"error": {
"code": "INVALID_CRON",
"message": "Invalid CRON expression",
"details": {
"expression": "invalid * * * *",
"field": "minute",
"reason": "Expected number or special character"
}
}
}
Resolution: Use a valid 5-field CRON expression (minute hour day month weekday).
INVALID_TIMESTAMP
Status: 400
{
"success": false,
"error": {
"code": "INVALID_TIMESTAMP",
"message": "Requested timestamp is outside the retention window",
"details": {
"requestedTimestamp": "2024-01-01T00:00:00Z",
"oldestAvailable": "2024-01-08T10:00:00Z",
"latestAvailable": "2024-01-15T10:30:00Z"
}
}
}
Resolution: Use a timestamp within the PITR retention window.
Operation Errors
BACKUP_IN_PROGRESS
Status: 409
{
"success": false,
"error": {
"code": "BACKUP_IN_PROGRESS",
"message": "A backup is already in progress for this project",
"details": {
"activeBackupId": "bkp_abc123",
"startedAt": "2024-01-15T10:00:00Z"
}
}
}
Resolution: Wait for the current backup to complete or cancel it.
RESTORE_IN_PROGRESS
Status: 409
{
"success": false,
"error": {
"code": "RESTORE_IN_PROGRESS",
"message": "A restore operation is already in progress",
"details": {
"activeRestoreId": "restore_abc123"
}
}
}
RESTORE_FAILED
Status: 500
{
"success": false,
"error": {
"code": "RESTORE_FAILED",
"message": "Failed to restore backup",
"details": {
"reason": "Insufficient permissions on target project",
"documentsRestored": 5000,
"failedAt": "users/user_5001"
}
}
}
Resolution: Check target project permissions and retry.
SCHEDULE_CONFLICT
Status: 409
{
"success": false,
"error": {
"code": "SCHEDULE_CONFLICT",
"message": "A schedule already exists for this project at the same time"
}
}
Resolution: Use a different CRON expression or modify the existing schedule.
Firebase/GCP Errors
INVALID_CREDENTIALS
Status: 400
{
"success": false,
"error": {
"code": "INVALID_CREDENTIALS",
"message": "Failed to connect to Firebase project",
"details": {
"reason": "Token expired or revoked"
}
}
}
Resolution: Re-authenticate the Firebase project connection.
IAM_PERMISSION_DENIED
Status: 403
{
"success": false,
"error": {
"code": "IAM_PERMISSION_DENIED",
"message": "Missing required IAM permissions",
"details": {
"missing": [
"roles/datastore.importExportAdmin",
"roles/firebase.viewer"
]
}
}
}
Resolution: Grant the required IAM roles in Google Cloud Console.
AUDIT_LOGS_REQUIRED
Status: 400
{
"success": false,
"error": {
"code": "AUDIT_LOGS_REQUIRED",
"message": "Firebase audit logs must be enabled for PITR",
"details": {
"instructions": "Enable audit logs in Google Cloud Console"
}
}
}
Resolution: Enable Firestore audit logs in GCP IAM & Admin > Audit Logs.
FIREBASE_CONNECTION_FAILED
Status: 502
{
"success": false,
"error": {
"code": "FIREBASE_CONNECTION_FAILED",
"message": "Failed to connect to Firebase",
"details": {
"firebaseProjectId": "my-project",
"reason": "Network timeout"
}
}
}
Resolution: Check network connectivity and Firebase project status.
Storage Errors
BUCKET_NOT_FOUND
Status: 404
{
"success": false,
"error": {
"code": "BUCKET_NOT_FOUND",
"message": "Bucket 'my-bucket' does not exist or is not accessible"
}
}
STORAGE_ACCESS_DENIED
Status: 403
{
"success": false,
"error": {
"code": "STORAGE_ACCESS_DENIED",
"message": "Access denied to storage bucket",
"details": {
"bucket": "my-bucket",
"operation": "write"
}
}
}
Resolution: Verify storage credentials have read/write permissions.
FILE_NOT_ORPHAN
Status: 400
{
"success": false,
"error": {
"code": "FILE_NOT_ORPHAN",
"message": "File is associated with a backup and cannot be deleted directly"
}
}
Resolution: Delete the backup record first to orphan the file.
STORAGE_UPLOAD_FAILED
Status: 500
{
"success": false,
"error": {
"code": "STORAGE_UPLOAD_FAILED",
"message": "Failed to upload backup to storage",
"details": {
"storageType": "S3",
"bucket": "my-bucket",
"reason": "Request timeout"
}
}
}
Organization Errors
INVITATION_EXISTS
Status: 409
{
"success": false,
"error": {
"code": "INVITATION_EXISTS",
"message": "An invitation already exists for this email"
}
}
Resolution: Cancel the existing invitation or wait for it to expire.
INVITATION_EXPIRED
Status: 400
{
"success": false,
"error": {
"code": "INVITATION_EXPIRED",
"message": "This invitation has expired",
"details": {
"expiredAt": "2024-01-15T00:00:00Z"
}
}
}
Resolution: Request a new invitation from an organization admin.
CANNOT_REMOVE_OWNER
Status: 400
{
"success": false,
"error": {
"code": "CANNOT_REMOVE_OWNER",
"message": "Cannot remove the organization owner. Transfer ownership first."
}
}
Resolution: Transfer ownership to another member before leaving.
MEMBER_EXISTS
Status: 409
{
"success": false,
"error": {
"code": "MEMBER_EXISTS",
"message": "User is already a member of this organization"
}
}
LAST_ADMIN
Status: 400
{
"success": false,
"error": {
"code": "LAST_ADMIN",
"message": "Cannot remove the last admin. Promote another member first."
}
}
Rate Limiting
RATE_LIMIT_EXCEEDED
Status: 429
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests",
"details": {
"limit": 100,
"window": "1m",
"retryAfter": 45
}
}
}
Headers:
Retry-After: 45
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705312845
Resolution: Wait for retryAfter seconds before retrying.
Server Errors
INTERNAL_ERROR
Status: 500
{
"success": false,
"error": {
"code": "INTERNAL_ERROR",
"message": "An unexpected error occurred",
"details": {
"requestId": "req_abc123xyz"
}
}
}
Resolution: Retry the request. If persistent, contact support with the requestId.
SERVICE_UNAVAILABLE
Status: 503
{
"success": false,
"error": {
"code": "SERVICE_UNAVAILABLE",
"message": "Service temporarily unavailable",
"details": {
"reason": "maintenance",
"estimatedRecovery": "2024-01-15T12:00:00Z"
}
}
}
Resolution: Wait for scheduled maintenance to complete.
DATABASE_ERROR
Status: 500
{
"success": false,
"error": {
"code": "DATABASE_ERROR",
"message": "Database operation failed"
}
}
Resolution: Retry the request. This is typically a transient error.
Error Handling Best Practices
1. Always Check Response Status
const response = await fetch('/api/v1/backups', options);
const data = await response.json();
if (!data.success) {
console.error(`Error ${data.error.code}: ${data.error.message}`);
// Handle specific error codes
switch (data.error.code) {
case 'TOKEN_EXPIRED':
await refreshToken();
break;
case 'RATE_LIMIT_EXCEEDED':
await sleep(data.error.details.retryAfter * 1000);
break;
default:
showErrorToUser(data.error.message);
}
}
2. Implement Retry Logic
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url, options);
const data = await response.json();
if (data.success) return data;
// Don't retry client errors (4xx)
if (response.status >= 400 && response.status < 500) {
throw new Error(data.error.message);
}
// Retry server errors (5xx)
await sleep(Math.pow(2, i) * 1000); // Exponential backoff
} catch (error) {
if (i === maxRetries - 1) throw error;
}
}
}
3. Handle Rate Limits
async function handleRateLimit(response) {
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
console.log(`Rate limited. Retrying in ${retryAfter}s`);
await sleep(retryAfter * 1000);
return true; // Signal to retry
}
return false;
}
4. Log Errors for Debugging
function logError(error, context) {
console.error({
code: error.code,
message: error.message,
details: error.details,
context,
timestamp: new Date().toISOString()
});
}
Related
- Authentication - Auth error handling
- API Overview - Request/response format
- Webhooks - Error event notifications