Overview
The Twigz API provides comprehensive error handling with structured error responses, proper HTTP status codes, and detailed error information to help developers build robust applications.
All API errors follow a consistent structure:
{
"error" : "Human-readable error message" ,
"code" : "MACHINE_READABLE_ERROR_CODE" ,
"details" : {
"field" : "specific field errors" ,
"context" : "additional context"
},
"timestamp" : 1640995200000 ,
"requestId" : "req_123456789"
}
HTTP Status Codes
2xx Success 200 - OK
201 - Created
204 - No Content
4xx Client Errors 400 - Bad Request
401 - Unauthorized
403 - Forbidden
404 - Not Found
409 - Conflict
5xx Server Errors 500 - Internal Server Error
502 - Bad Gateway
503 - Service Unavailable
Payment Errors 402 - Payment Required
422 - Payment Failed
424 - Payment Processing
Common Error Types
Authentication Errors
401 - Authentication Required
When : User is not authenticated{
"error" : "Authentication required" ,
"code" : "UNAUTHENTICATED" ,
"message" : "Please sign in to access this resource"
}
Solution : Redirect to login page or show authentication prompt
403 - Insufficient Permissions
When : User lacks required permissions{
"error" : "Insufficient permissions" ,
"code" : "FORBIDDEN" ,
"details" : {
"requiredRole" : "store_owner" ,
"userRole" : "customer" ,
"resource" : "store_management"
}
}
Solution : Show access denied message or upgrade account prompt
Validation Errors
When : Request data is invalid{
"error" : "Validation failed" ,
"code" : "VALIDATION_ERROR" ,
"details" : {
"name" : "Product name must be between 1 and 100 characters" ,
"price" : "Price must be a positive number" ,
"category" : "Category ID is required"
}
}
Solution : Show field-specific error messages to user
When : Resource already exists or conflicts{
"error" : "Store already exists for this user" ,
"code" : "RESOURCE_CONFLICT" ,
"details" : {
"existingStoreId" : "j123456789" ,
"storeName" : "Mario's Pizza"
}
}
Solution : Redirect to existing resource or offer update option
Business Logic Errors
When : Not enough inventory for order{
"error" : "Insufficient stock for one or more items" ,
"code" : "INSUFFICIENT_STOCK" ,
"details" : {
"productId" : "p123456789" ,
"productName" : "Pizza Margherita" ,
"requested" : 5 ,
"available" : 3
}
}
Solution : Update cart quantities or remove unavailable items
When : Store is not accepting orders{
"error" : "Store is not accepting orders" ,
"code" : "STORE_INACTIVE" ,
"details" : {
"storeId" : "j123456789" ,
"storeName" : "Mario's Pizza" ,
"status" : "temporarily_closed" ,
"reason" : "Store is temporarily closed for maintenance"
}
}
Solution : Show store status and suggest alternatives
Payment Errors
When : Payment method declined{
"error" : "Payment declined" ,
"code" : "PAYMENT_DECLINED" ,
"details" : {
"declineCode" : "insufficient_funds" ,
"paymentMethod" : "card" ,
"lastFour" : "4242"
}
}
Solution : Ask user to try different payment method
422 - Payment Processing Failed
When : Payment processing error{
"error" : "Payment processing failed" ,
"code" : "PAYMENT_PROCESSING_ERROR" ,
"details" : {
"paymentIntentId" : "pi_123456789" ,
"stripeError" : "Your card was declined" ,
"retryable" : true
}
}
Solution : Allow retry or suggest alternative payment method
Error Handling Patterns
React Error Boundary
import React from 'react' ;
import { ConvexError } from 'convex/values' ;
interface ErrorBoundaryState {
hasError : boolean ;
error : Error | null ;
}
class ApiErrorBoundary extends React . Component <
React . PropsWithChildren <{}>,
ErrorBoundaryState
> {
constructor ( props : React . PropsWithChildren <{}>) {
super ( props );
this . state = { hasError: false , error: null };
}
static getDerivedStateFromError ( error : Error ) : ErrorBoundaryState {
return { hasError: true , error };
}
componentDidCatch ( error : Error , errorInfo : React . ErrorInfo ) {
console . error ( 'API Error caught by boundary:' , error , errorInfo );
// Report to error tracking service
// reportError(error, errorInfo);
}
render () {
if ( this . state . hasError ) {
const error = this . state . error ;
if ( error instanceof ConvexError ) {
// Handle Convex-specific errors
return (
< div className = "bg-red-50 p-4 rounded-lg" >
< h2 className = "text-lg font-semibold text-red-900 mb-2" >
Something went wrong
</ h2 >
< p className = "text-red-700" > {error. data } </ p >
< button
onClick = {() => this.setState({ hasError : false , error : null })}
className = "mt-2 px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700"
>
Try Again
</ button >
</ div >
);
}
// Handle other errors
return (
< div className = "bg-gray-50 p-4 rounded-lg" >
< h2 className = "text-lg font-semibold text-gray-900 mb-2" >
Unexpected Error
</ h2 >
< p className = "text-gray-700" >
An unexpected error occurred . Please refresh the page or contact support .
</ p >
< button
onClick = {() => window.location.reload()}
className = "mt-2 px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
>
Refresh Page
</ button >
</ div >
);
}
return this . props . children ;
}
}
export default ApiErrorBoundary ;
Retry Mechanisms
Automatic Retry
Network Error Handling
async function withRetry < T >(
fn : () => Promise < T >,
maxRetries : number = 3 ,
delay : number = 1000
) : Promise < T > {
let lastError : any ;
for ( let attempt = 1 ; attempt <= maxRetries ; attempt ++ ) {
try {
return await fn ();
} catch ( error ) {
lastError = error ;
// Don't retry on client errors (4xx)
if ( error instanceof ConvexError ) {
const errorData = error . data ;
if ( typeof errorData === 'object' && errorData . status >= 400 && errorData . status < 500 ) {
throw error ;
}
}
if ( attempt === maxRetries ) {
throw lastError ;
}
// Exponential backoff
await new Promise ( resolve => setTimeout ( resolve , delay * Math . pow ( 2 , attempt - 1 )));
}
}
throw lastError ;
}
// Usage
const result = await withRetry ( async () => {
return await convex . mutation ( api . shared . products . createProduct , productData );
}, 3 , 1000 );
The API uses Convex’s built-in error handling which provides structured errors with proper typing and automatic retry mechanisms for transient failures.
Always handle errors gracefully in your UI and provide clear feedback to users about what went wrong and how to resolve it.