Error Handling
Error Handling and Debugging
Learn how to handle errors gracefully, understand error codes, and debug API integration issues effectively.
HTTP Status Codes
| Code | Meaning | Description |
|---|---|---|
| 200 | OK | Request successful |
| 401 | Unauthorized | Invalid or missing API credentials |
| 403 | Forbidden | API key lacks required permissions |
| 404 | Not Found | Resource doesn't exist (table, record, etc.) |
| 412 | Precondition Failed | Subscription limit or feature disabled |
| 422 | Unprocessable Entity | Validation error - invalid data format |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server-side error |
Error Response Format
All error responses follow this structure:
{
"type": "error",
"msg": "Human-readable error message",
"status": 422,
"errors": {
"field_slug": ["Field-specific error message"]
}
}
Common Errors and Solutions
401 Unauthorized
Error: "API Not Found"
{
"type": "error",
"msg": "API Not Found",
"status": 401
}
Cause: Invalid API credentials (App ID, App Key, or App Secret)
Solution:
- Verify credentials in Settings → API Keys
- Check for typos when copying credentials
- Ensure headers are named exactly:
X-Tadabase-App-id,X-Tadabase-App-Key,X-Tadabase-App-Secret - Regenerate API key if credentials were compromised
Error: "APP Not Found"
{
"type": "error",
"msg": "APP Not Found",
"status": 401
}
Cause: Incorrect App ID
Solution:
- Check App ID in Settings → API Keys
- App ID is also in your URL:
yourapp.tadabase.io/builder/{appId}
Error: "API Disabled"
{
"type": "error",
"msg": "API Disabled",
"status": 401
}
Cause: API key was disabled
Solution:
- Go to Settings → API Keys
- Re-enable the API key or generate a new one
403 Forbidden
Error: "Permission Denied"
{
"type": "error",
"msg": "Permission Denied",
"status": 403
}
Cause: API key lacks required permission
Solution:
- Edit API key in Settings → API Keys
- Enable the required permissions:
allow_getfor reading recordsallow_editfor creating/updatingallow_deletefor deletingallow_taskfor tasks
404 Not Found
Error: "Table Not Found"
{
"type": "error",
"msg": "Table Not Found",
"status": 404
}
Cause: Invalid table ID in URL
Solution:
- Use
GET /api/v1/data-tablesto list all tables and get correct IDs - Verify table ID is correct (check for typos)
Error: "Record Not Found"
{
"type": "error",
"msg": "Record Not Found",
"status": 404
}
Cause: Record doesn't exist or was deleted
Solution:
- Verify record ID is correct
- Check if record was deleted
- Ensure you're using the encoded record ID, not a display value
422 Validation Error
{
"type": "error",
"msg": "Validation failed",
"status": 422,
"errors": {
"email": ["Email is required", "Email must be valid"],
"status": ["This field is unique"]
}
}
Cause: Data doesn't meet validation rules
Solution:
- Check the
errorsobject for field-specific issues - Ensure all required fields are included
- Verify data formats match field types
- Check unique field constraints
Common Validation Errors
| Error Message | Cause | Solution |
|---|---|---|
| "This field is required" | Missing required field | Include the field in your request |
| "This field is unique" | Duplicate value in unique field | Use a different value or update existing record |
| "Email must be valid" | Invalid email format | Use proper email format: user@example.com |
| "Invalid date format" | Wrong date format | Use YYYY-MM-DD format |
429 Rate Limit Exceeded
{
"type": "error",
"msg": "Too Many Attempts In Minute",
"status": 429
}
Cause: Exceeded per-minute rate limit
Solution:
- Check
X-Retry-Afterheader for wait time - Implement rate limiting in your code
- See Rate Limiting guide for strategies
{
"type": "error",
"msg": "Too Many Attempts In Day",
"status": 429
}
Cause: Exceeded daily rate limit
Solution:
- Wait 24 hours for reset
- Optimize requests (batch operations, caching)
- Consider upgrading subscription plan
412 Precondition Failed
{
"type": "error",
"msg": "Feature not available in your plan",
"status": 412
}
Cause: Feature requires higher subscription tier
Solution:
- Upgrade subscription plan
- Contact support for plan details
500 Internal Server Error
{
"type": "error",
"msg": "Internal Server Error",
"status": 500
}
Cause: Server-side error
Solution:
- Retry the request (may be temporary)
- If persistent, contact Tadabase support with request details
- Implement exponential backoff retry logic
Implementing Error Handling
Basic Error Handling
async function makeApiRequest(url, options) {
try {
const response = await fetch(url, options);
const data = await response.json();
if (data.type === 'error') {
console.error('API Error:', data.msg);
if (data.errors) {
console.error('Field Errors:', data.errors);
}
throw new Error(data.msg);
}
return data;
} catch (error) {
console.error('Request failed:', error);
throw error;
}
}
Comprehensive Error Handler
class APIError extends Error {
constructor(status, message, errors = null) {
super(message);
this.status = status;
this.errors = errors;
this.name = 'APIError';
}
}
async function makeApiRequest(url, options, maxRetries = 3) {
let attempt = 0;
while (attempt setTimeout(resolve, retryAfter * 1000));
attempt++;
continue;
}
// Handle server errors with retry
if (response.status >= 500) {
const delay = Math.pow(2, attempt) * 1000;
console.log(`Server error. Retrying in ${delay/1000}s...`);
await new Promise(resolve => setTimeout(resolve, delay));
attempt++;
continue;
}
// Handle client errors (no retry)
if (data.type === 'error') {
throw new APIError(response.status, data.msg, data.errors);
}
return data;
} catch (error) {
if (error instanceof APIError) {
throw error;
}
// Network or other errors
if (attempt >= maxRetries - 1) {
throw error;
}
const delay = Math.pow(2, attempt) * 1000;
console.log(`Request failed. Retrying in ${delay/1000}s...`);
await new Promise(resolve => setTimeout(resolve, delay));
attempt++;
}
}
throw new Error('Max retries exceeded');
}
// Usage
try {
const data = await makeApiRequest(url, options);
console.log('Success:', data);
} catch (error) {
if (error instanceof APIError) {
console.error(`API Error ${error.status}: ${error.message}`);
if (error.errors) {
console.error('Validation errors:', error.errors);
}
} else {
console.error('Request failed:', error);
}
}
Debugging Tips
1. Log Full Request and Response
async function debugApiRequest(url, options) {
console.log('Request:', {
url,
method: options.method || 'GET',
headers: options.headers,
body: options.body
});
const response = await fetch(url, options);
const data = await response.json();
console.log('Response:', {
status: response.status,
headers: Object.fromEntries(response.headers),
body: data
});
return data;
}
2. Check Request Headers
Ensure all three authentication headers are present and correct:
const headers = {
'X-Tadabase-App-id': appId,
'X-Tadabase-App-Key': appKey,
'X-Tadabase-App-Secret': appSecret
};
// Verify headers before sending
Object.keys(headers).forEach(key => {
if (!headers[key]) {
throw new Error(`Missing header: ${key}`);
}
});
3. Validate Data Before Sending
function validateRecord(record, requiredFields) {
const missing = requiredFields.filter(field => !record[field]);
if (missing.length > 0) {
throw new Error(`Missing required fields: ${missing.join(', ')}`);
}
return true;
}
// Usage
validateRecord(newRecord, ['first_name', 'last_name', 'email']);
4. Test with API Tester First
Before writing code, test endpoints in the built-in API Tester:
- Go to
/apiin your Tadabase instance - Test the endpoint manually
- View the exact request and response
- Export working request as curl or Postman
5. Use Postman or curl for Debugging
Test requests outside your application:
curl -X GET 'https://api.tadabase.io/api/v1/data-tables/lGArg7rmR6/records' \
-H 'X-Tadabase-App-id: your_app_id' \
-H 'X-Tadabase-App-Key: your_app_key' \
-H 'X-Tadabase-App-Secret: your_app_secret' \
-v # Verbose output for debugging
6. Check API Logs
If your API key has allow_log permission enabled:
- Go to Settings → Logs in the Builder
- Select "API Logs"
- View detailed request/response logs
- Filter by date range
Common Integration Issues
Issue: Filters Not Working
Symptoms: Filter returns all records instead of filtered subset
Debug Steps:
- Check you're using
operator(notcondition) in filter items - Check you're using
val(notvalue) for values - Verify
field_idexists using/fieldsendpoint - Check response
total_itemscount
Issue: Record Creation Fails Silently
Symptoms: 200 response but record not created
Debug Steps:
- Check API key has
allow_editpermission - Verify Content-Type header is set correctly
- Check for validation errors in response
- Ensure field slugs are correct
Issue: Connection Fields Not Saving
Symptoms: Connection field remains empty
Debug Steps:
- Verify you're using encoded record IDs, not display values
- Check connection field accepts multiple vs single values
- Use array format:
["id1", "id2"] - Ensure connected records exist
Best Practices
- Always Handle Errors: Implement comprehensive error handling in production code
- Log Errors: Log errors with context for debugging
- Retry Transient Errors: Implement retry logic for 429 and 500 errors
- Validate Before Sending: Catch errors in your code before making API calls
- Monitor API Health: Track error rates and response times
- Test Error Scenarios: Test how your code handles different error types
Next Steps
Learn best practices for building reliable and secure API integrations:
Master security, performance optimization, and integration best practices.
We'd love to hear your feedback.