OpenSEO Error Codes: Complete Reference and Handling Guide

OpenSEO defines a closed set of typed error codes in src/shared/error-codes.ts that should be thrown as AppError instances, filtered through the shouldCaptureAppErrorCode helper to separate reportable system issues from expected user errors, and mapped to appropriate HTTP responses.

OpenSEO is an open-source SEO platform that enforces a strict error taxonomy to keep telemetry clean and API responses predictable. Every available error code is declared in src/shared/error-codes.ts and validated with a Zod enum. Understanding these codes and how to handle them is essential for building reliable integrations and maintaining healthy monitoring pipelines.

Complete List of OpenSEO Error Codes

The following error codes represent every failure mode currently exposed by the platform:

  • UNAUTHENTICATED — The request lacks valid authentication credentials. Typical scenario: missing or expired session token.
  • AUTH_CONFIG_MISSING — Required authentication configuration is absent. Typical scenario: API keys not set.
  • PAYMENT_REQUIRED — The account does not have an active payment method. Typical scenario: subscription expired.
  • INSUFFICIENT_CREDITS — The account has run out of allotted credits. Typical scenario: exceeded usage quota.
  • FORBIDDEN — The authenticated user is not allowed to perform the action. Typical scenario: permission restrictions.
  • NOT_FOUND — The requested resource does not exist. Typical scenario: invalid IDs or deleted projects.
  • AUDIT_CAPACITY_REACHED — The audit queue is full for the tenant. Typical scenario: too many concurrent audits.
  • AUDIT_PAGE_LIMIT_EXCEEDED — The audit exceeds the page-count limit. Typical scenario: crawling a site that is too large.
  • AUDIT_ALREADY_RUNNING — An audit is already in progress for the same target. Typical scenario: duplicate request.
  • VALIDATION_ERROR — Input validation failed. Typical scenario: malformed request payloads.
  • CRAWL_TARGET_BLOCKED — The crawler was blocked by robots.txt or HTTP 403. Typical scenario: target site disallows crawling.
  • BACKLINKS_BILLING_ISSUE — Billing problem specific to the backlinks service. Typical scenario: account not provisioned for backlinks.
  • AI_SEARCH_BILLING_ISSUE — Billing problem specific to the AI-search service. Typical scenario: account not provisioned for AI-search.
  • DATAFORSEO_AUTH_FAILED — Authentication with the DataForSEO provider failed. Typical scenario: invalid DataForSEO credentials.
  • RATE_LIMITED — The client hit a rate limit. Typical scenario: too many requests in a short window.
  • UPSTREAM_UNAVAILABLE — An upstream dependency is unreachable. Typical scenario: external API outage.
  • CONFLICT — A resource conflict occurred. Typical scenario: simultaneous updates.
  • INTERNAL_ERROR — An unexpected server error. Typical scenario: unhandled exceptions or bugs.

Reportable vs Non-Reportable Errors

OpenSEO splits its error taxonomy into reportable and non-reportable codes. The non-reportable set is stored in NON_REPORTABLE_ERROR_CODES inside src/shared/error-codes.ts (lines 28-37). These codes represent expected, user-facing conditions such as authentication failures, quota limits, and validation problems. They are intentionally omitted from telemetry and crash reporting.

To decide whether an error should be captured, use the shouldCaptureAppErrorCode helper exported from the same file:

// src/shared/error-codes.ts
export function shouldCaptureAppErrorCode(
  code: ErrorCode | null | undefined,
): boolean {
  return code == null || !NON_REPORTABLE_ERROR_CODES.has(code);
}

If shouldCaptureAppErrorCode returns true, the error is forwarded to your monitoring pipeline. If it returns false, the error is treated as a known condition and ignored for reporting purposes.

How to Handle OpenSEO Error Codes

Throw Typed Errors with AppError

Server-side code should always raise an AppError (or a subclass) with one of the defined codes. This guarantees that downstream middleware can inspect the code property and choose the correct response.

// Example in a server function
import { AppError } from "@/server/lib/errors";

export async function getProject(id: string) {
  const project = await db.project.findUnique({ where: { id } });

  if (!project) {
    // NOT_FOUND is non-reportable; user sees a friendly message
    throw new AppError("NOT_FOUND", `Project ${id} does not exist`);
  }

  return project;
}

Filter Errors at the Boundary

When catching errors in middleware or API handlers, extract the code property and pass it to shouldCaptureAppErrorCode. This prevents expected errors from polluting your exception tracker.

import { shouldCaptureAppErrorCode } from "@/shared/error-codes";

export async function errorHandlingMiddleware(ctx, next) {
  try {
    await next();
  } catch (err: any) {
    const code = err?.code as ErrorCode | undefined;

    if (shouldCaptureAppErrorCode(code)) {
      // Forward to telemetry (e.g., Sentry)
      await reportError(err);
    }

    // Convert to HTTP response
    ctx.response.status = err?.status ?? 500;
    ctx.response.body = { error: err.message, code };
  }
}

Map Error Codes to HTTP Responses

Each code should be translated to an appropriate HTTP status. For example, UNAUTHENTICATED maps to 401, FORBIDDEN to 403, NOT_FOUND to 404, VALIDATION_ERROR to 400, and INTERNAL_ERROR to 500. The AppError constructor in src/server/lib/errors.ts accepts a status code or infers one directly from the enum, so this mapping is typically handled automatically.

Consume Errors on the Client

Front-end code should read the code field from the JSON error payload and branch accordingly. Redirect to login for UNAUTHENTICATED, show a friendly alert for NOT_FOUND, or surface a generic message for unexpected failures.

async function fetchProject(id: string) {
  const resp = await fetch(`/api/project/${id}`);
  const data = await resp.json();

  if (!resp.ok) {
    switch (data.code) {
      case "UNAUTHENTICATED":
        window.location.href = "/login";
        break;
      case "NOT_FOUND":
        alert("Project not found.");
        break;
      default:
        console.error("Unexpected error:", data);
    }
  }

  return data;
}

Key Source Files for Error Handling

The following files define and implement the OpenSEO error taxonomy:

  • src/shared/error-codes.ts — Central definition of all error codes, the Zod schema, the NON_REPORTABLE_ERROR_CODES set, and the shouldCaptureAppErrorCode helper.
  • src/server/lib/errors.ts — The AppError class used throughout server functions to attach an error code and HTTP status.
  • src/middleware/errorHandling.ts — Centralized middleware that applies shouldCaptureAppErrorCode to decide whether to forward errors to telemetry and formats HTTP responses.
  • src/serverFunctions/*.ts — Example usages of AppError across rank-tracking, billing, and AI-search features.
  • src/shared/error-codes.test.ts — Unit tests confirming the behavior of shouldCaptureAppErrorCode and validation of the enum.

Summary

  • OpenSEO exposes a closed, Zod-validated set of error codes in src/shared/error-codes.ts.
  • Always throw AppError (or subclasses) with a defined code so downstream code can inspect the failure mode.
  • Use shouldCaptureAppErrorCode to keep expected user errors out of telemetry and focus alerting on abnormal conditions.
  • Map each code to an appropriate HTTP status in your API layer.
  • Read the code field in client-side fetch handlers to trigger specific UI flows.

Frequently Asked Questions

What is the difference between reportable and non-reportable OpenSEO error codes?

Reportable codes indicate unexpected or systemic problems that should be sent to telemetry, while non-reportable codes represent anticipated user-facing conditions such as authentication failures or quota limits. The NON_REPORTABLE_ERROR_CODES set in src/shared/error-codes.ts (lines 28-37) lists the excluded codes, and the shouldCaptureAppErrorCode helper uses this set to filter them out.

How does the shouldCaptureAppErrorCode function decide whether to capture an error?

The function returns true when the supplied code is null, undefined, or not present in NON_REPORTABLE_ERROR_CODES. If the code exists in that set, the function returns false and the error should be handled gracefully instead of forwarded to crash reporting.

Which HTTP status should I return for a VALIDATION_ERROR in OpenSEO?

A VALIDATION_ERROR should map to HTTP 400 Bad Request. The AppError constructor in src/server/lib/errors.ts can infer this status automatically from the error code enum, or you can supply it explicitly when instantiating the error.

Where are OpenSEO error codes defined and tested?

All codes are defined in src/shared/error-codes.ts alongside the Zod enum and shouldCaptureAppErrorCode helper. Their behavior is verified in src/shared/error-codes.test.ts, which confirms correct validation and the reportable-vs-non-reportable logic.

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 →