How to Debug Issues in Open-SEO: A Complete Guide to Layered Error Handling
To debug issues in Open-SEO, trace errors through its five-layer architecture (Client, Server Functions, Middleware, Services, and Workflows) using centralized error handling, structured logging, and PostHog telemetry.
Open-SEO is an SEO automation platform built on a layered architecture that separates concerns across the client, server, and background jobs. Understanding how errors propagate through each layer—from React UI crashes to workflow failures—is essential for rapid diagnosis. This guide covers the exact file paths, middleware logic, and debugging commands you need to resolve issues efficiently.
Understanding Open-SEO's Five-Layer Architecture
Before debugging, identify which layer is failing:
| Layer | Responsibility | Typical Failure Points |
|---|---|---|
| Client | React UI, TanStack Query & Form | UI crashes, network request failures, malformed input |
| Server Functions | Exported functions called from the UI (src/serverFunctions/*.ts) |
Validation errors, third-party API failures |
| Middleware | Global error handling and request preprocessing (src/middleware/*.ts) |
Uncaught exceptions, request parsing problems |
| Services | Business-logic helpers (e.g., src/server/features/*/services/*.ts) |
Database issues, rate-limit handling, internal logic bugs |
| Workflows | Long-running background jobs (src/server/workflows/*.ts) |
Cron failures, step-wise errors, workflow termination |
Each layer has specific debugging protocols. Start by checking which boundary the error crosses.
Centralized Error Handling in errorHandlingMiddleware
All server-side code in Open-SEO runs through errorHandlingMiddleware located at src/middleware/errorHandling.ts. This middleware acts as the primary safety net for errors escaping from server functions and services.
The middleware executes the following logic:
- Wraps requests in a
try/catchblock to intercept thrown errors - Detects validator errors (TanStack schema violations) and converts them to an
AppErrorwith codeVALIDATION_ERROR(lines 28-42) - Filters telemetry using
shouldCaptureAppErrorCodefromsrc/shared/error-codes.tsto decide whether the error should be reported to PostHog (lines 44-47) - Captures telemetry by calling
captureServerErrorto ship error data tosrc/server/lib/posthog.ts(line 19) - Sanitizes output through
toClientErrorto ensure the UI receives a safe JSON payload without sensitive internals (line 59)
If you see an error logged in Cloudflare Workers logs but no entry in PostHog, check NON_REPORTABLE_ERROR_CODES in src/shared/error-codes.ts. Common filtered codes include UNAUTHENTICATED and VALIDATION_ERROR.
Client-Side Debugging Strategies
When debugging the React frontend, verify three key areas:
- Network inspector – Confirm the request URL, HTTP method, and payload match the server function signature
- TanStack Query devtools – Inspect query keys, fetch status, and cached data for stale or missing values
- React Error Boundaries – If the UI crashes completely, check the boundary's
errorprop for stack traces
Client errors originate from toClientError in src/server/lib/errors.ts. The response shape is predictable:
{
"error": "VALIDATION_ERROR",
"message": "...",
"details": { ... }
}
To reproduce client issues locally, invoke the same server function via pnpm dev and watch the console output for the full stack trace.
Debugging Server Functions
Server functions live in src/serverFunctions/*.ts and serve as thin wrappers around business logic. They are validated by TanStack's schema before execution.
To debug a specific function in isolation:
# Run a single function directly
pnpm tsx src/serverFunctions/searchPerformance.ts <input-json>
If the function throws, the stack trace points to the underlying service (e.g., src/server/features/keywords/services/research/serp.ts).
Common server-side pitfalls:
- Rate-limit errors – Look for
errorCode: "RATE_LIMITED"insrc/shared/error-codes.ts - DataForSEO authentication – Missing
DATAFORSEO_API_KEYbinding triggersDATAFORSEO_AUTH_FAILED
You can also test endpoints manually using curl:
curl -X POST http://localhost:5173/api/searchPerformance \
-H "Content-Type: application/json" \
-d '{"projectId":"abc","domain":"example.com"}'
If the response contains { "error": "VALIDATION_ERROR" }, the payload failed schema validation before reaching business logic.
Background Workflow Debugging
Workflows orchestrate multi-step jobs like site audits and rank checks using the TanStack Server Workflow framework. They reside in src/server/workflows/*.ts.
For example, SiteAuditWorkflow.ts logs failures at line 71:
console.error(`Audit ${auditId} failed:`, error);
To trace a broken workflow:
- Locate the specific workflow file (e.g.,
src/server/workflows/RankCheckWorkflow.ts) - Search Cloudflare Workers logs for the audit ID or run ID
- Look for
captureServerErrorcalls, which include metadata likeerrorCode,method, andpath
Trigger workflows manually during development:
pnpm tsx src/server/workflows/RankCheckWorkflow.ts --audit-id=12345
Logging and Observability Patterns
Every module in Open-SEO uses a dual-logging strategy: console.error for immediate debugging and captureServerError for aggregated observability.
Standard pattern from service files:
// Example from a service layer
try {
await someAsyncOp();
} catch (err) {
console.error("[rank-tracking] auto-metrics-refresh failed:", err);
await captureServerError(err, { errorCode: "INTERNAL_ERROR" });
throw err;
}
Search the repository for console.error( to find all hotspots (e.g., src/server/workflows/SiteAuditWorkflow.ts line 71).
PostHog integration (src/server/lib/posthog.ts) receives all non-filtered errors with these fields:
errorCode(fromsrc/shared/error-codes.ts)- Request metadata (
method,path) - Optional
detailssupplied by theAppError
View these events in the PostHog UI under "Server Errors" and correlate timestamps with Cloudflare Workers logs.
Custom error handling in services should follow this pattern:
import { AppError } from "@/server/lib/errors";
import { captureServerError } from "@/server/lib/posthog";
export async function fetchBacklinks(projectId: string) {
try {
const res = await dataforseoClient.backlinks(projectId);
return res;
} catch (err) {
console.error("backlinks.service error:", err);
await captureServerError(err, { errorCode: "DATAFORSEO_AUTH_FAILED" });
throw new AppError("BACKLINKS_BILLING_ISSUE", { projectId });
}
}
Testing for Rapid Feedback
Open-SEO ships with Vitest for unit tests and Playwright for end-to-end testing. Failing tests often surface the same code paths that produce production errors.
# Fast unit tests
pnpm test
# Slow E2E UI tests
pnpm test:e2e
Investigate failing test files (e.g., src/shared/error-codes.test.ts) to understand expected error handling behavior and boundary conditions.
Summary
- Use
errorHandlingMiddleware(src/middleware/errorHandling.ts) to understand how server errors are caught, logged, and sanitized before reaching the client. - Check
error-codes.tsto see if your error is inNON_REPORTABLE_ERROR_CODES, which explains missing PostHog entries. - Debug server functions by running them directly with
pnpm tsxand inspecting the stack trace to locate service-level bugs. - Trace workflows by searching logs for the specific audit ID and examining
console.errorstatements insrc/server/workflows/*.ts. - Leverage dual logging with
console.errorfor immediate feedback andcaptureServerErrorfor production telemetry insrc/server/lib/posthog.ts. - Validate fixes using the existing test suite to ensure error handling paths remain robust.
Frequently Asked Questions
How do I know if an error is being reported to PostHog?
Errors are only reported to PostHog if shouldCaptureAppErrorCode in src/shared/error-codes.ts returns true for the specific error code. If you see an error in Cloudflare Workers logs but not in PostHog, the code is likely listed in NON_REPORTABLE_ERROR_CODES (such as UNAUTHENTICATED or VALIDATION_ERROR). You can adjust the filtering logic after confirming the error's production impact.
What does a VALIDATION_ERROR response mean?
A VALIDATION_ERROR indicates that the request payload failed TanStack schema validation before reaching the server function's business logic. This error originates in src/middleware/errorHandling.ts (lines 28-42) and means your input JSON does not match the expected Zod or Valibot schema defined in the server function. Check the details field in the response to identify which specific fields failed validation.
How can I debug a failing background workflow?
Locate the specific workflow file in src/server/workflows/*.ts and search the Cloudflare Workers logs for the audit ID or run ID associated with the failed job. Look for console.error statements that log the specific error object, and check for calls to captureServerError which include metadata like errorCode and request path. You can also trigger workflows manually in development using pnpm tsx src/server/workflows/WorkflowName.ts --flag=value.
Where should I add custom error handling in my service code?
Add custom error handling in src/server/features/*/services/*.ts files by wrapping external API calls or database operations in try/catch blocks. Log immediate debugging information with console.error, then call captureServerError (from src/server/lib/posthog.ts) with the appropriate error code before re-throwing or wrapping the error in an AppError (defined in src/server/lib/errors.ts) to maintain the error handling contract expected by the middleware.
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 →