How OpenSEO's Error Handling System Classifies and Reports Issues
OpenSEO uses a layered middleware approach that classifies errors into validation, application-defined, and unexpected runtime categories, then selectively reports them to PostHog analytics while sanitizing client-facing messages.
The every-app/open-seo repository implements a robust error handling system that ensures type-safe error classification across server functions. This system distinguishes between schema validation failures, custom application errors, and unexpected runtime exceptions to determine which issues require analytics tracking and which details are safe to expose to clients.
Error Classification Architecture
OpenSEO categorizes all server-side errors into three distinct buckets. Each category follows a specific detection path and reporting rule set defined in the core middleware and error library files.
Validation Errors
Validation errors originate from TanStack's schema validators. When input validation fails, the middleware detects these through the isValidatorError helper in src/middleware/errorHandling.ts, which checks for JSON-encoded schema issues within the error object. These errors receive the code VALIDATION_ERROR and are converted into standardized AppError instances for consistent handling.
Application-Defined Errors
Custom business logic errors use the AppError class defined in src/server/lib/errors.ts. The asAppError function attempts to map caught errors to known error codes by matching error messages against the ErrorCode enum defined in src/shared/error-codes.ts. Common application codes include UNAUTHENTICATED, PAYMENT_REQUIRED, and BACKLINKS_BILLING_ISSUE.
Unexpected Runtime Errors
Any error that fails validation detection and cannot be mapped to a known application code becomes a generic INTERNAL_ERROR. These represent unhandled exceptions and always trigger analytics capture since they indicate potential system defects requiring immediate attention.
The Middleware Pipeline
The errorHandlingMiddleware in src/middleware/errorHandling.ts serves as the central entry point for all server functions. This TanStack-Start function-level middleware wraps every handler in a try/catch block to ensure consistent error processing across the application.
// Registering the middleware in your route configuration
import { errorHandlingMiddleware } from "@/middleware/errorHandling";
export const route = {
middleware: [errorHandlingMiddleware],
// additional route configuration...
};
Analytics and Reporting Logic
Not all errors warrant analytics tracking. The shouldCaptureAppErrorCode function in src/shared/error-codes.ts maintains a whitelist of NON_REPORTABLE_ERROR_CODES including UNAUTHENTICATED, VALIDATION_ERROR, and audit-related limits.
When an error is capturable, the middleware invokes captureServerError from src/server/lib/posthog.ts to forward structured error reports to PostHog. This enables team monitoring of system health without logging sensitive authentication failures or routine validation mistakes.
Client-Safe Error Sanitization
The toClientError function in src/server/lib/errors.ts strips internal error details before sending responses to the browser. Unless an error code appears in the CLIENT_DETAIL_ERROR_CODES list (currently limited to AUTH_CONFIG_MISSING), clients receive only the error code or a generic INTERNAL_ERROR message. This prevents information leakage while maintaining debugging capabilities for specific configuration issues.
Implementation Examples
The following patterns demonstrate how to work with OpenSEO's error handling system in server functions:
// Automatic validation error handling
export const someServerFn = createServerFn()
.input(z.object({ url: z.string().url() }))
.handler(async ({ input }) => {
// If input fails schema validation, TanStack throws a plain Error
// that the middleware converts to an AppError with code VALIDATION_ERROR.
// No manual error handling required.
});
// Raising custom application errors
import { AppError } from "@/server/lib/errors";
export const fetchBacklinks = createServerFn()
.handler(async () => {
const ok = await someExternalCall();
if (!ok) {
// Recognized by asAppError and reported based on its code whitelist status
throw new AppError("BACKLINKS_BILLING_ISSUE", "Billing problem");
}
});
Summary
- Centralized Middleware:
src/middleware/errorHandling.tswraps all server functions to provide consistent error handling across the application. - Validation Detection: The
isValidatorErrorhelper identifies schema validation failures and assigns theVALIDATION_ERRORcode. - Error Normalization:
asAppErrormaps unknown errors to known codes while preserving unmapped errors as unexpected runtime exceptions. - Selective Analytics:
shouldCaptureAppErrorCodefilters outNON_REPORTABLE_ERROR_CODESbefore sending data to PostHog viacaptureServerError. - Security Sanitization:
toClientErrorensures only safe error details reach the client, defaulting toINTERNAL_ERRORfor non-whitelisted codes.
Frequently Asked Questions
How does OpenSEO differentiate between validation and application errors?
OpenSEO uses the isValidatorError helper in src/middleware/errorHandling.ts to detect validation errors by checking for JSON-encoded schema issues in the error object. Application errors are identified when asAppError successfully matches the error message against known codes in src/shared/error-codes.ts. If neither check succeeds, the system treats the error as an unexpected runtime exception.
Which error codes does OpenSEO exclude from PostHog analytics?
The NON_REPORTABLE_ERROR_CODES whitelist in src/shared/error-codes.ts excludes authentication failures like UNAUTHENTICATED, validation errors marked as VALIDATION_ERROR, and audit-related limit errors. The shouldCaptureAppErrorCode function returns false for these codes, preventing them from being forwarded to captureServerError in src/server/lib/posthog.ts.
What happens when an error doesn't match any known error code?
When asAppError cannot map an error to a known ErrorCode, the system leaves the error unchanged. If the error also fails the isValidatorError check, the middleware treats it as an unexpected runtime error. These errors are always captured for analytics (since they lack a whitelist code) and are converted to INTERNAL_ERROR before reaching the client via toClientError.
How can I throw a custom application error in OpenSEO?
Import the AppError class from @/server/lib/errors and instantiate it with a valid error code and message. When thrown within a server function wrapped by errorHandlingMiddleware, the error will be recognized by asAppError, evaluated by shouldCaptureAppErrorCode for analytics eligibility, and sanitized by toClientError before reaching the client.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →