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:
UNAUTHENTICATEDandFORBIDDENfor auth failuresAUTH_CONFIG_MISSINGfor missing DataForSEO credentialsRATE_LIMITEDfor API throttlingVALIDATION_ERRORfor input issuesNOT_FOUNDfor missing resourcesINTERNAL_ERRORfor 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
- Centralized error architecture: All OpenSEO errors flow through
src/server/lib/errors.tsasAppErrorinstances with typedErrorCodevalues fromsrc/shared/error-codes.ts. - Safe client exposure: The
toClientErrorfunction filters error details to prevent leaking sensitive implementation details, exposing only whitelisted codes likeAUTH_CONFIG_MISSING. - Health endpoint diagnostics: The
/api/healthroute aggregates setup checks fromsrc/server/lib/setup-status.ts, returning JSON that identifies failing components such asdataforseo:errorordatabase:error. - Common error patterns: Authentication issues originate in
src/server/middleware.ts, validation errors insrc/server/lib/domainUtils.ts, and DataForSEO-specific problems insrc/server/lib/dataforseo/client.tsandbusiness.ts. - Self-hosting verification: Use the health check endpoint alongside
docs/SELF_HOSTING_DOCKER.mdandpnpm exec wrangler tailto diagnose configuration issues in production environments.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →