Error Handling
Learn how to handle errors gracefully in your Flow API integration.
Error Types
Validation Errors (400)
Invalid request data:
try {
await flow.posts.create({
channelId: '', // Invalid: empty
content: 'Hello',
});
} catch (error) {
if (error instanceof FlowError && error.status === 400) {
error.details?.forEach(detail => {
console.error(`${detail.field}: ${detail.message}`);
});
}
}
Authentication Errors (401)
Invalid or missing API key:
try {
await flow.posts.list();
} catch (error) {
if (error instanceof FlowError && error.status === 401) {
console.error('Invalid API key');
// Regenerate API key or check configuration
}
}
Authorization Errors (403)
Insufficient permissions:
try {
await flow.posts.create({ channelId: 'channel_123', content: 'Hello' });
} catch (error) {
if (error instanceof FlowError && error.status === 403) {
console.error('Insufficient permissions');
// Check API key permissions
}
}
Not Found Errors (404)
Resource not found:
try {
await flow.posts.get('invalid_id');
} catch (error) {
if (error instanceof FlowError && error.status === 404) {
console.error('Post not found');
// Handle missing resource
}
}
Rate Limit Errors (429)
Rate limit exceeded:
try {
await flow.posts.list();
} catch (error) {
if (error instanceof FlowError && error.status === 429) {
const waitTime = error.retryAfter || 60;
console.log(`Rate limited. Wait ${waitTime} seconds`);
await new Promise(resolve => setTimeout(resolve, waitTime * 1000));
// Retry request
}
}
Server Errors (500, 503)
Internal server errors:
try {
await flow.posts.create({ channelId: 'channel_123', content: 'Hello' });
} catch (error) {
if (error instanceof FlowError && (error.status === 500 || error.status === 503)) {
// Retry with exponential backoff
await retryWithBackoff(() =>
flow.posts.create({ channelId: 'channel_123', content: 'Hello' })
);
}
}
Retry Logic
Exponential Backoff
async function retryWithBackoff<T>(
fn: () => Promise<T>,
maxRetries = 3
): Promise<T> {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error instanceof FlowError) {
// Don't retry client errors
if (error.status >= 400 && error.status < 500 && error.status !== 429) {
throw error;
}
// Retry server errors and rate limits
if (error.status >= 500 || error.status === 429 || error.status === 503) {
const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
const retryAfter = error.retryAfter ? error.retryAfter * 1000 : delay;
await new Promise(resolve => setTimeout(resolve, retryAfter));
continue;
}
}
throw error;
}
}
throw new Error('Max retries exceeded');
}
Usage
const post = await retryWithBackoff(() =>
flow.posts.create({
channelId: 'channel_123',
content: 'Hello!',
})
);
Error Logging
Log Request IDs
try {
await flow.posts.create({ channelId: 'channel_123', content: 'Hello' });
} catch (error) {
if (error instanceof FlowError && error.requestId) {
console.error(`Request ID: ${error.requestId}`, error);
// Include request_id when contacting support
}
}
Structured Logging
function logError(error: FlowError, context: Record<string, any>) {
logger.error({
error: {
type: error.type,
code: error.code,
message: error.message,
status: error.status,
requestId: error.requestId,
details: error.details,
},
context,
});
}
Best Practices
- Always handle errors - Never ignore errors
- Use typed errors - Use SDK error types when available
- Implement retries - For transient errors (429, 500, 503)
- Log request IDs - For debugging and support
- Validate before sending - Prevent validation errors
- Monitor error rates - Alert on high error rates
Next Steps
- Learn about Rate Limits
- Understand Best Practices Guide
- Explore API Reference Overview