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
| Code | Name | Cause | Solution |
|---|---|---|---|
| 400 | Bad Request | Invalid payload or parameter | Check request body |
| 401 | Unauthorized | Invalid or missing API key | Verify API key |
| 403 | Forbidden | Insufficient permissions | Check key scopes |
| 404 | Not Found | Invalid route or resource | Verify endpoint URL |
| 422 | Unprocessable Entity | Validation failed | Check field values |
| 429 | Rate Limited | Too many requests | Implement backoff |
5xx Server Errors
| Code | Name | Cause | Solution |
|---|---|---|---|
| 500 | Internal Error | Platform bug | Contact support |
| 502 | Bad Gateway | Service unavailable | Retry later |
| 503 | Service Unavailable | Maintenance/overload | Retry with backoff |
| 504 | Gateway Timeout | Slow response | Retry |
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
- Latency Accounting — Performance monitoring
- API Reference — API details
- SDK Quickstart — SDK usage
Was this page helpful?
Your feedback helps us prioritize docs improvements weekly.