Error Handling
All Auva APIs return errors in a consistent JSON format. Understanding these patterns helps you build resilient integrations.
Error Response Format
Every error response follows this structure:
text
{
"error": "Error Type",
"message": "Human-readable description of what went wrong"
}
HTTP Status Codes
| Code | Meaning | When It Happens |
|---|---|---|
400 | Bad Request | Invalid request body, missing required fields |
401 | Unauthorized | Missing or expired access token |
403 | Forbidden | Valid token but insufficient permissions |
404 | Not Found | Resource doesn't exist |
409 | Conflict | Duplicate resource (e.g., username taken) |
422 | Unprocessable Entity | Validation failed (e.g., invalid email format) |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Something broke on our end |
Common Error Scenarios
Invalid Credentials
text
// POST /auth/login with wrong password
{
"error": "Unauthorized",
"message": "Invalid email or password"
}
Token Expired
text
// GET /user/me with expired token
{
"error": "Unauthorized",
"message": "Token expired"
}
Action: Call POST /auth/refresh to get a new access token.
Validation Error
text
// POST /auth/register with invalid data
{
"error": "Validation Error",
"message": "Email must be a valid email address"
}
Resource Not Found
text
// GET /api/links/nonexistent-id
{
"error": "Not Found",
"message": "Link not found"
}
Username Taken
text
// POST /auth/register with existing username
{
"error": "Conflict",
"message": "Username is already taken"
}
Error Handling Pattern
Here's a robust error handling pattern for TypeScript:
text
type ApiError = {
error: string;
message: string;
};
async function apiCall<T>(url: string, options?: RequestInit): Promise<T> {
const response = await fetch(url, {
...options,
credentials: 'include',
headers: {
'Content-Type': 'application/json',
...options?.headers,
},
});
if (!response.ok) {
const error: ApiError = await response.json().catch(() => ({
error: 'Unknown Error',
message: 'An unexpected error occurred',
}));
switch (response.status) {
case 401:
// Try refresh, then retry
throw new AuthError(error.message);
case 429:
// Implement retry with backoff
throw new RateLimitError(error.message);
default:
throw new ApiCallError(error.message, response.status);
}
}
return response.json();
}
Always parse error responses as JSON and display the message field to users. The error field is for programmatic handling, while message is human-readable.