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.ts wraps all server functions to provide consistent error handling across the application.
  • Validation Detection: The isValidatorError helper identifies schema validation failures and assigns the VALIDATION_ERROR code.
  • Error Normalization: asAppError maps unknown errors to known codes while preserving unmapped errors as unexpected runtime exceptions.
  • Selective Analytics: shouldCaptureAppErrorCode filters out NON_REPORTABLE_ERROR_CODES before sending data to PostHog via captureServerError.
  • Security Sanitization: toClientError ensures only safe error details reach the client, defaulting to INTERNAL_ERROR for 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →