Error Codes Reference
This document describes all error responses returned by the BoardAPI, including HTTP status codes, error formats, and troubleshooting guidance.
Error Response Format
All API errors follow a consistent JSON structure:
{
"statusCode": 400,
"message": "Validation failed",
"error": "Bad Request",
"details": [
{
"field": "title",
"message": "title must be longer than or equal to 1 characters"
}
],
"timestamp": "2025-11-19T10:30:45.123Z",
"path": "/api/v1/boards"
}Response Fields
| Field | Type | Description |
|---|---|---|
statusCode | number | HTTP status code (400, 401, 404, etc.) |
message | string | Human-readable error description |
error | string | Error type name (e.g., "Bad Request", "Unauthorized") |
details | array | Optional array of validation errors or additional context |
timestamp | string | ISO 8601 timestamp of when error occurred |
path | string | API endpoint path where error occurred |
HTTP Status Codes
2xx Success
| Code | Name | Description |
|---|---|---|
200 | OK | Request succeeded |
201 | Created | Resource created successfully |
204 | No Content | Request succeeded with no response body |
4xx Client Errors
400 Bad Request
Cause: Invalid request parameters, malformed JSON, or validation errors.
Example:
{
"statusCode": 400,
"message": ["title must be longer than or equal to 1 characters"],
"error": "Bad Request"
}Common Scenarios:
- Missing required fields
- Invalid data types (string instead of number)
- Validation constraints not met
- Malformed JSON syntax
How to Fix:
- Check all required fields are present
- Verify data types match API specification
- Review validation rules in API documentation
- Validate JSON syntax using a linter
401 Unauthorized
Cause: Missing, invalid, or expired authentication credentials.
Example:
{
"statusCode": 401,
"message": "Unauthorized",
"error": "Unauthorized"
}Common Scenarios:
- Missing
X-API-Keyheader - Invalid API key
- Expired JWT token
- Invalid board access token
- Token signature verification failed
How to Fix:
- Ensure
X-API-Keyheader is present and correct - Check token expiration time
- Regenerate API key if compromised
- Verify JWT token format and signature
Code Example:
// ❌ Wrong - Missing authentication
fetch('https://api.boardapi.io/api/v1/boards', {
method: 'POST',
body: JSON.stringify({ title: 'Test' })
});
// ✅ Correct - Include API key
fetch('https://api.boardapi.io/api/v1/boards', {
method: 'POST',
headers: {
'X-API-Key': 'your-api-key',
'Content-Type': 'application/json'
},
body: JSON.stringify({ title: 'Test' })
});403 Forbidden
Cause: Authenticated but lacking permissions for the requested action.
Example:
{
"statusCode": 403,
"message": "Insufficient permissions",
"error": "Forbidden"
}Common Scenarios:
- Guest trying to delete a board (requires host role)
- Accessing organization resources from different organization
- Attempting admin actions without admin permissions
How to Fix:
- Check user role and permissions
- Use host token for admin operations
- Verify organization ID matches requested resource
404 Not Found
Cause: Requested resource does not exist.
Example:
{
"statusCode": 404,
"message": "Board not found",
"error": "Not Found"
}Common Scenarios:
- Invalid board UUID
- Board has been deleted
- Resource ID typo or incorrect format
- Accessing resource from different organization
How to Fix:
- Verify resource ID is correct
- Check if resource was deleted
- Confirm organization scope
- List all resources to find correct ID
409 Conflict
Cause: Request conflicts with current state of the server.
Example:
{
"statusCode": 409,
"message": "Email already exists",
"error": "Conflict"
}Common Scenarios:
- Duplicate email during user registration
- Concurrent updates to same resource
- Attempting to create resource that already exists
How to Fix:
- Check for existing resources before creation
- Implement optimistic locking for concurrent updates
- Use unique identifiers
410 Gone
Cause: Resource existed but has been permanently removed or expired.
Example:
{
"statusCode": 410,
"message": "Board has expired",
"error": "Gone"
}Common Scenarios:
- Accessing expired board (past
expires_attimestamp) - Resource explicitly marked as deleted/gone
How to Fix:
- Create a new board
- Check expiration dates before access
- Archive boards instead of deleting
413 Payload Too Large
Cause: Request body exceeds size limit.
Example:
{
"statusCode": 413,
"message": "Request entity too large",
"error": "Payload Too Large"
}Limits:
- Request body: 10MB
- File uploads: 50MB
How to Fix:
- Reduce request payload size
- Split large requests into smaller chunks
- Compress file uploads
422 Unprocessable Entity
Cause: Request is well-formed but contains semantic errors.
Example:
{
"statusCode": 422,
"message": "Invalid object type schema",
"error": "Unprocessable Entity",
"details": [
{
"field": "data.word",
"message": "required property missing"
}
]
}Common Scenarios:
- JSON schema validation failures
- Business logic constraints violated
- Invalid enum values
How to Fix:
- Review object type schemas
- Check business logic rules
- Validate against API specification
429 Too Many Requests
Cause: Rate limit exceeded.
Example:
{
"statusCode": 429,
"message": "Rate limit exceeded. Try again in 3600 seconds.",
"error": "Too Many Requests"
}Rate Limits:
- Standard Plan: 1,000 requests/hour
- Premium Plan: 10,000 requests/hour
Response Headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1732012345How to Fix:
- Implement exponential backoff
- Respect
X-RateLimit-Remainingheader - Upgrade to higher plan
- Cache responses to reduce API calls
Code Example:
async function makeRequest(url, options, retries = 3) {
try {
const response = await fetch(url, options);
if (response.status === 429 && retries > 0) {
const resetTime = response.headers.get('X-RateLimit-Reset');
const waitTime = (resetTime * 1000) - Date.now();
console.log(`Rate limited. Waiting ${waitTime}ms...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
return makeRequest(url, options, retries - 1);
}
return response;
} catch (error) {
throw error;
}
}5xx Server Errors
500 Internal Server Error
Cause: Unexpected server error.
Example:
{
"statusCode": 500,
"message": "Internal server error",
"error": "Internal Server Error"
}Common Scenarios:
- Database connection failure
- Unhandled exception in server code
- Third-party service unavailable
How to Fix:
- Retry request after brief delay
- Check API status page
- Contact support if persistent
- Report error with request ID
502 Bad Gateway
Cause: Invalid response from upstream server.
Example:
{
"statusCode": 502,
"message": "Bad Gateway",
"error": "Bad Gateway"
}How to Fix:
- Retry request (likely temporary)
- Check API status page
- Wait for service recovery
503 Service Unavailable
Cause: Service temporarily unavailable (maintenance, overload).
Example:
{
"statusCode": 503,
"message": "Service temporarily unavailable",
"error": "Service Unavailable"
}How to Fix:
- Retry with exponential backoff
- Check status page for maintenance schedule
- Wait for service to recover
504 Gateway Timeout
Cause: Request timeout while waiting for upstream server.
Example:
{
"statusCode": 504,
"message": "Gateway timeout",
"error": "Gateway Timeout"
}How to Fix:
- Retry request
- Reduce request complexity
- Contact support if persistent
Error Handling Best Practices
1. Always Check Status Codes
async function makeApiRequest(url, options) {
const response = await fetch(url, options);
if (!response.ok) {
const error = await response.json();
throw new ApiError(error.statusCode, error.message, error);
}
return response.json();
}
class ApiError extends Error {
constructor(statusCode, message, details) {
super(message);
this.statusCode = statusCode;
this.details = details;
this.name = 'ApiError';
}
}2. Implement Retry Logic
async function retryRequest(fn, maxRetries = 3, delay = 1000) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (i === maxRetries - 1) throw error;
// Retry on 5xx errors or network issues
if (error.statusCode >= 500 || error.name === 'NetworkError') {
const backoff = delay * Math.pow(2, i); // Exponential backoff
await new Promise(resolve => setTimeout(resolve, backoff));
continue;
}
throw error; // Don't retry 4xx errors
}
}
}3. Log Errors for Debugging
function logError(error, context) {
console.error('API Error:', {
statusCode: error.statusCode,
message: error.message,
path: error.details?.path,
timestamp: error.details?.timestamp,
context: context
});
// Send to error tracking service
if (window.Sentry) {
Sentry.captureException(error, {
extra: { context, errorDetails: error.details }
});
}
}4. Display User-Friendly Messages
function getUserFriendlyMessage(error) {
const messages = {
400: 'Please check your input and try again.',
401: 'Please log in to continue.',
403: 'You don\'t have permission to perform this action.',
404: 'The requested resource was not found.',
429: 'Too many requests. Please try again later.',
500: 'Something went wrong. Please try again.',
503: 'Service is temporarily unavailable. Please try again later.'
};
return messages[error.statusCode] || 'An unexpected error occurred.';
}Common Error Scenarios
Scenario 1: Board Not Found
Problem:
GET /api/v1/boards/invalid-uuid
→ 404 Not Found: "Board not found"Solution:
try {
const board = await getBoard(uuid);
} catch (error) {
if (error.statusCode === 404) {
console.log('Board does not exist or was deleted');
// Redirect to board list or show creation dialog
}
}Scenario 2: Token Expired
Problem:
POST /api/v1/boards
X-API-Key: expired-key
→ 401 Unauthorized: "Invalid or expired token"Solution:
// Regenerate API key
PATCH /api/v1/organizations/:id/regenerate-api-key
// Or refresh JWT token (for user authentication)
POST /auth/refresh
{
"refresh_token": "..."
}Scenario 3: Validation Error
Problem:
POST /api/v1/boards
{
"title": ""
}
→ 400 Bad Request: "title must be longer than or equal to 1 characters"Solution:
// Validate input before sending
function validateBoardInput(data) {
const errors = [];
if (!data.title || data.title.length < 1) {
errors.push('Title is required');
}
if (data.expires_in_hours && data.expires_in_hours < 1) {
errors.push('Expiration must be at least 1 hour');
}
return errors;
}
const errors = validateBoardInput(formData);
if (errors.length > 0) {
showValidationErrors(errors);
} else {
await createBoard(formData);
}Troubleshooting Guide
Quick Diagnostic Checklist
- [ ] Is the API endpoint URL correct?
- [ ] Is authentication header present and valid?
- [ ] Is request body valid JSON?
- [ ] Are all required fields included?
- [ ] Are data types correct (string vs number)?
- [ ] Is rate limit exceeded? (check headers)
- [ ] Is the server healthy? (check status page)
- [ ] Are CORS headers correct (for browser requests)?
Debugging Tools
cURL Test:
# Test API endpoint with verbose output
curl -v \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
'https://api.boardapi.io/api/v1/boards'Check Response Headers:
curl -I \
-H "X-API-Key: your-api-key" \
'https://api.boardapi.io/api/v1/boards'Validate JSON:
# Use jq to validate JSON syntax
echo '{"title":"test"}' | jq .Support
If you encounter persistent errors:
- Check API Status: https://status.boardapi.io
- Review Documentation: https://docs.boardapi.io
- Contact Support: support@boardapi.io
- Report Bugs: https://github.com/boardapi/issues
Include the following in support requests:
- Error response (full JSON)
- Request details (method, endpoint, headers)
- Timestamp of error
- Steps to reproduce
Related Documentation
- Authentication API - Authentication errors and solutions
- Boards API - Board-specific error scenarios
- Rate Limiting - Rate limit handling
- Monitoring API - Error tracking and monitoring