--- title: "Error Handling" description: "Standards for handling errors across the Formbricks codebase" icon: "triangle-exclamation" --- ## Overview At Formbricks, we follow consistent error handling patterns to ensure reliability, debuggability, and maintainability across our codebase. This document outlines our standard approaches to error handling. ## Core Principles 1. **Type Safety**: Use typed errors and results 2. **Meaningful Messages**: Provide clear, actionable error messages 3. **Proper Propagation**: Handle or propagate errors appropriately 4. **Logging**: Ensure errors are properly logged for debugging 5. **Recovery**: Implement graceful fallbacks where possible ## Standard Error Types We maintain a set of standardized error types for different scenarios: ```typescript export interface ApiErrorResponse { code: | "not_found" | "gone" | "bad_request" | "internal_server_error" | "unauthorized" | "method_not_allowed" | "not_authenticated" | "forbidden" | "network_error"; message: string; status: number; url: URL; details?: Record; responseMessage?: string; } ``` ## Error Handling Patterns ### API Error Handling For API endpoints: ```typescript export const GET = async (request: Request) => { try { const authentication = await authenticateRequest(request); if (!authentication) return responses.notAuthenticatedResponse(); const data = await fetchData(authentication.environmentId!); return responses.successResponse(data); } catch (error) { if (error instanceof DatabaseError) { return responses.badRequestResponse(error.message); } throw error; } }; ``` ### Client-Side Error Handling For client-side operations: ```typescript const handleOperation = async () => { const result = await performAction(); if (!result.ok) { logger.error(`Operation failed: ${result.error.message}`); toast.error("Operation failed. Please try again."); return; } // Process successful result processResult(result.data); }; ``` ## Best Practices 1. **Never Swallow Errors** - Always handle or propagate errors - Log errors appropriately for debugging - Use error boundaries in React components 2. **Type Safety** - Use typed error responses - Leverage TypeScript for compile-time error checking - Define clear error interfaces 3. **Error Messages** - Include relevant context in error messages - Make messages actionable for developers - Use consistent error formatting 4. **Error Recovery** - Implement fallback behaviors where appropriate - Gracefully degrade functionality when possible - Provide user feedback for recoverable errors 5. **Documentation** - Document expected errors in function JSDoc - Include error handling in code examples - Keep error handling documentation up to date ## Testing Error Scenarios Always include error case testing: ```typescript describe("fetchEnvironmentState()", () => { test("returns err(...) on network error", async () => { const mockNetworkError = { code: "network_error", message: "Timeout", responseMessage: "Network fail", }; const result = await fetchEnvironmentState(); expect(result.ok).toBe(false); if (!result.ok) { expect(result.error.code).toBe(mockNetworkError.code); expect(result.error.message).toBe(mockNetworkError.message); } }); }); ``` These standards ensure consistent, reliable error handling across the Formbricks codebase while maintaining good developer experience and system reliability.