Operations

Browse docs

Operations

Tap to expand

Contribute

OperationsUpdated 2026-03-18

Error Taxonomy and Troubleshooting

Complete guide to RetainDB API errors, error codes, and step-by-step debugging procedures.

Applies to: API v1, SDK v3+

This guide helps you identify, understand, and resolve errors in production.


Error Code Reference

4xx Client Errors

CodeNameCauseSolution
400Bad RequestInvalid payload or parameterCheck request body
401UnauthorizedInvalid or missing API keyVerify API key
403ForbiddenInsufficient permissionsCheck key scopes
404Not FoundInvalid route or resourceVerify endpoint URL
422Unprocessable EntityValidation failedCheck field values
429Rate LimitedToo many requestsImplement backoff

5xx Server Errors

CodeNameCauseSolution
500Internal ErrorPlatform bugContact support
502Bad GatewayService unavailableRetry later
503Service UnavailableMaintenance/overloadRetry with backoff
504Gateway TimeoutSlow responseRetry

SDK Error Handling

Basic Try-Catch

typescript
try {
  await client.memory.add({ user_id: "user@example.com", content: "Hello" });
} catch (error) {
  console.error("Error:", error.code, error.message);
}

Error Properties

typescript
interface RetainDBError {
  code: string;          // Error code (e.g., "RATE_LIMITED")
  message: string;       // Human-readable message
  status: number;        // HTTP status code
  trace_id?: string;    // For debugging
  retry_after?: number; // Seconds to wait (for 429)
}

Common Errors and Solutions

Invalid API Key (401)

Error:

json
{
  "error": "invalid_api_key",
  "message": "API key is invalid"
}

Solution:

typescript
// Verify key is set correctly
console.log(process.env.RETAINDB_API_KEY);

// Check key format (should start with sk_live_ or sk_test_)
const key = process.env.RETAINDB_API_KEY;
if (!key?.startsWith("sk_")) {
  throw new Error("Invalid key format");
}

Rate Limited (429)

Error:

json
{
  "error": "rate_limit_exceeded",
  "message": "Too many requests",
  "retry_after": 60
}

Solution:

typescript
// Implement exponential backoff
async function withRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === "rate_limit_exceeded") {
        const delay = error.retry_after * 1000 || Math.pow(2, i) * 1000;
        console.log(`Rate limited, retrying in ${delay}ms`);
        await new Promise(r => setTimeout(r, delay));
      } else {
        throw error;
      }
    }
  }
}

Invalid Memory Type (400)

Error:

json
{
  "error": "invalid_memory_type",
  "message": "Memory type must be one of: factual, preference, event, relationship, opinion, goal, instruction"
}

Solution:

typescript
// Use valid memory types
const validTypes = ["factual", "preference", "event", "relationship", "opinion", "goal", "instruction"];

if (!validTypes.includes(memoryType)) {
  throw new Error(`Invalid memory type: ${memoryType}`);
}

Debugging with Trace IDs

Every error includes a trace_id for support:

typescript
try {
  await client.memory.search({ user_id: "user@example.com", query: "test" });
} catch (error) {
  console.error("Trace ID:", error.trace_id);
  // Contact support with this ID
}

Retry Strategy

What to Retry

typescript
const RETRYABLE_CODES = [
  "NETWORK_ERROR",
  "TIMEOUT",
  "RATE_LIMITED",
  "SERVICE_UNAVAILABLE",
  "INTERNAL_ERROR",
];

const NON_RETRYABLE_CODES = [
  "INVALID_API_KEY",
  "INVALID_REQUEST",
  "NOT_FOUND",
  "PERMISSION_DENIED",
];

async function handleError(error) {
  if (RETRYABLE_CODES.includes(error.code)) {
    // Retry with backoff
    await exponentialBackoff(() => retryOperation());
  } else {
    // Don't retry
    console.error("Non-retryable error:", error.code);
  }
}

Retry with Jitter

typescript
async function retryWithJitter(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      
      // Exponential backoff with jitter
      const baseDelay = Math.pow(2, i) * 1000;
      const jitter = Math.random() * 1000;
      await new Promise(r => setTimeout(r, baseDelay + jitter));
    }
  }
}

Health Checks

Basic Health Check

typescript
async function healthCheck() {
  try {
    await client.memory.search({
      user_id: "health-check",
      query: "test",
    });
    return { status: "healthy" };
  } catch (error) {
    return { status: "unhealthy", error: error.code };
  }
}

Detailed Health Check

typescript
async function detailedHealth() {
  const checks = {
    api: await checkAPI(),
    search: await checkSearch(),
    write: await checkWrite(),
  };

  const allHealthy = Object.values(checks).every(c => c.healthy);
  return { healthy: allHealthy, checks };
}

Logging Best Practices

typescript
// Always log with context
console.error({
  timestamp: new Date().toISOString(),
  error_code: error.code,
  error_message: error.message,
  trace_id: error.trace_id,
  user_id: userId,
  operation: "memory.search",
  latency_ms: latency,
});

Next step

Was this page helpful?

Your feedback helps us prioritize docs improvements weekly.