How to Troubleshoot Common OpenSEO Errors: Complete Diagnostic Guide

OpenSEO errors are centrally handled through the AppError class in src/server/lib/errors.ts with typed error codes defined in src/shared/error-codes.ts, and can be diagnosed using the /api/health endpoint which aggregates setup checks from src/server/lib/setup-status.ts.

OpenSEO (every-app/open-seo) is built on a modular server-side architecture that centralizes error handling to help developers quickly identify configuration issues, authentication failures, and upstream provider problems. Understanding how to troubleshoot common OpenSEO errors requires familiarity with the typed error system and the health-check diagnostics built into the platform.

Understanding OpenSEO's Error Architecture

OpenSEO implements a strict error-handling pattern that prevents internal stack traces from leaking while providing actionable feedback to developers.

Centralized Error Handling in errors.ts

All runtime exceptions flow through src/server/lib/errors.ts, which exports the AppError class. Every error is either thrown as an AppError (carrying a typed ErrorCode) or wrapped by the asAppError utility function. This ensures consistent error shapes throughout the application.

The toClientError function filters which error details reach the client. Only whitelisted codes like AUTH_CONFIG_MISSING return full messages; others return generic safe responses to prevent information leakage.

Typed Error Codes with Zod Validation

The errorCodeSchema in src/shared/error-codes.ts defines all valid error conditions using Zod validation. This guarantees that only predefined literals can be emitted, including:

  • UNAUTHENTICATED and FORBIDDEN for auth failures
  • AUTH_CONFIG_MISSING for missing DataForSEO credentials
  • RATE_LIMITED for API throttling
  • VALIDATION_ERROR for input issues
  • NOT_FOUND for missing resources
  • INTERNAL_ERROR for upstream provider failures

Common OpenSEO Errors and Diagnostic Paths

When troubleshooting OpenSEO errors, match your symptom to the specific error code and source location.

Authentication Failures (UNAUTHENTICATED / FORBIDDEN)

Symptoms: API calls return 401 or 403 status codes.

Source: Auth middleware in src/server/middleware.ts.

Resolution: Verify the request includes a valid Authorization header. Check the token-validation logic in the middleware to ensure the bearer token is correctly formatted and unexpired.

Missing DataForSEO Credentials (AUTH_CONFIG_MISSING)

Symptoms: Health checks fail with dataforseo:error or API calls refuse to initialize.

Source: Setup check in src/server/lib/setup-status.ts.

Resolution: Confirm the environment variable DATAFORSEO_API_KEY is correctly defined. See docs/DATAFORSEO_API_KEY.md for configuration instructions. The health endpoint will specifically flag this as AUTH_CONFIG_MISSING in its JSON response.

Rate Limiting from DataForSEO (RATE_LIMITED)

Symptoms: HTTP 429 responses when fetching SERP data.

Source: DataForSEO client wrapper in src/server/lib/dataforseo/client.ts.

Resolution: Inspect the Retry-After header in the response and implement exponential backoff. The AppError thrown will include the code RATE_LIMITED when the upstream provider throttles requests.

Validation Errors (VALIDATION_ERROR)

Symptoms: "Invalid domain" messages in the UI or API responses.

Source: Domain validation utilities in src/server/lib/domainUtils.ts.

Resolution: Ensure domain inputs are fully qualified URLs including the scheme (e.g., https://example.com). Partial domains or missing protocols trigger this error during the validation step.

Rank Tracking Not Found (NOT_FOUND)

Symptoms: Rank-tracking configuration appears missing for existing projects.

Source: Rank-tracking services in src/server/features/rank-tracking/services/*.ts.

Resolution: Verify the project's rank-tracking entry exists in the database. For production debugging, run pnpm exec wrangler tail to view real-time Worker logs and confirm the record lookup logic.

DataForSEO Internal Errors (INTERNAL_ERROR)

Symptoms: Task creation succeeds but results retrieval fails or returns malformed data.

Source: DataForSEO business logic in src/server/lib/dataforseo/business.ts.

Resolution: Check that the DataForSEO response JSON includes the required task_id field. Missing task IDs indicate upstream API issues or malformed request payloads.

Using the Health Check Endpoint for Diagnostics

The /api/health route defined in src/routes/api/health.ts provides a centralized diagnostic interface for self-hosters. This endpoint calls performSetupChecks() from src/server/lib/setup-status.ts to verify:

  • Database connectivity
  • DataForSEO API key validity
  • Cloudflare bindings
  • Environment configuration completeness

The endpoint returns a concise JSON payload listing each component's status. Failing checks follow the pattern service:error (e.g., database:error, dataforseo:error), allowing you to pinpoint misconfigurations without digging through logs.

This health check runs the same validation logic as the Docker pre-flight script (scripts/selfhost-preflight.ts), ensuring consistency between startup checks and runtime diagnostics.

Practical Error Handling Examples

Safely Converting Errors for Client Responses

Use toClientError to prevent sensitive details from reaching the client:

import { toClientError } from "@/server/lib/errors";

try {
  // Server logic that might throw
  await fetchSerpData(params);
} catch (e) {
  // Returns generic message unless error is in whitelist
  const safeError = toClientError(e);
  console.error(safeError);
  
  return new Response(safeError.message, { status: 500 });
}

Implementing Custom Error Handling for DataForSEO

When integrating with the DataForSEO API, wrap responses in AppError instances:

import { AppError } from "@/server/lib/errors";

async function fetchSerp(params: SerpParams) {
  const resp = await fetch(`https://api.dataforseo.com/serp`, {
    method: 'POST',
    headers: { 'Authorization': `Basic ${apiKey}` },
    body: JSON.stringify(params)
  });
  
  if (!resp.ok) {
    const body = await resp.json();
    // Throw typed error with upstream message
    throw new AppError("DATAFORSEO_AUTH_FAILED", body.message);
  }
  
  return resp.json();
}

Health Check Implementation

The health endpoint implementation demonstrates how to aggregate system status:

import { createFileRoute } from "@tanstack/react-router";
import { performSetupChecks } from "@/server/lib/setup-status";

export const Route = createFileRoute("/api/health")({
  loader: async () => {
    const checks = await performSetupChecks();
    return new Response(JSON.stringify(checks), {
      headers: { "Content-Type": "application/json" },
    });
  },
});

Summary

Frequently Asked Questions

How do I verify my DataForSEO API key is configured correctly?

Check the /api/health endpoint response for a dataforseo:error status. If present, verify that the DATAFORSEO_API_KEY environment variable is set according to docs/DATAFORSEO_API_KEY.md. The health check runs the same validation as the startup pre-flight script, so a passing health check guarantees the key is valid.

What does the UNAUTHENTICATED error mean in OpenSEO?

The UNAUTHENTICATED error code indicates missing or invalid bearer tokens in the Authorization header, thrown by the auth middleware in src/server/middleware.ts. Unlike FORBIDDEN (which indicates valid authentication but insufficient permissions), UNAUTHENTICATED means the request lacks valid credentials entirely.

How can I safely expose error messages to the client without leaking stack traces?

Import toClientError from src/server/lib/errors.ts and wrap all caught exceptions before sending them to the client. This function only expands error messages for whitelisted codes (such as AUTH_CONFIG_MISSING), returning generic messages for all other errors to prevent exposing internal implementation details.

Where should I look for logs when troubleshooting rank-tracking issues?

For rank-tracking NOT_FOUND errors originating in src/server/features/rank-tracking/services/*.ts, run pnpm exec wrangler tail to view real-time Worker logs. This shows the actual database queries and DataForSEO API responses, helping you determine whether the project record is missing or the upstream task failed to create.

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 →