Skip to main content

Error Handling Reference

Last Updated: January 9, 2026 SDK Version: 0.29.0 Sources: src/resilience/types.ts, src/*/validators.ts, src/graph/types.ts

Overview​

Cortex uses structured errors with specific error codes for predictable error handling. Errors are categorized into:

  1. Validation Errors - Client-side validation (instant feedback)
  2. Resilience Errors - Overload protection (rate limits, circuit breaker)
  3. Graph Errors - Graph database operations
  4. Cascade Errors - Deletion cascade operations
  5. Convex Backend Errors - Backend operation failures

Import Error Classes:

import {
// Validation errors
MemoryValidationError,
ConversationValidationError,
FactsValidationError,
UserValidationError,
AgentValidationError,

// Resilience errors
CircuitOpenError,
RateLimitExceededError,
QueueFullError,
AcquireTimeoutError,

// Graph errors
GraphDatabaseError,
GraphConnectionError,
GraphQueryError,

// Other errors
A2ATimeoutError,
CascadeDeletionError,
} from "@cortexmemory/sdk";

Table of Contents​

  1. Error Class Hierarchy
  2. Error Handling Patterns
  3. Validation Errors
  4. Resilience Errors
  5. Graph Errors
  6. Other Errors
  7. Troubleshooting Guide

Error Class Hierarchy​

Error (native JavaScript)
├── ValidationError (client-side validation)
│ ├── MemoryValidationError
│ ├── ConversationValidationError
│ ├── FactsValidationError
│ ├── UserValidationError
│ ├── AgentValidationError
│ ├── SessionValidationError
│ ├── AuthValidationError
│ ├── ImmutableValidationError
│ ├── MutableValidationError
│ ├── GovernanceValidationError
│ ├── MemorySpaceValidationError
│ ├── ContextsValidationError
│ └── A2AValidationError
├── ResilienceError (resilience layer)
│ ├── RateLimitExceededError
│ ├── CircuitOpenError
│ ├── QueueFullError
│ └── AcquireTimeoutError
├── GraphDatabaseError (graph operations)
│ ├── GraphConnectionError
│ │ └── GraphAuthenticationError
│ ├── GraphQueryError
│ └── GraphNotFoundError
├── CascadeDeletionError
├── AgentCascadeDeletionError
├── A2ATimeoutError
└── ResumableStreamError

Error Handling Patterns​

Basic Error Handling​

import { MemoryValidationError, CircuitOpenError } from "@cortexmemory/sdk";

try {
await cortex.memory.remember({
memorySpaceId: "user-123-space",
conversationId: "conv-123",
userMessage: "My name is Alex",
agentResponse: "Nice to meet you, Alex!",
userId: "user-123",
userName: "Alex",
agentId: "assistant",
});
} catch (error) {
if (error instanceof MemoryValidationError) {
// Client-side validation error (instant)
console.error(`Validation: ${error.code}`);
console.error(`Field: ${error.field}`);
console.error(`Message: ${error.message}`);
} else if (error instanceof CircuitOpenError) {
// Backend is unhealthy
console.error("Service temporarily unavailable");
console.error(`Retry after: ${error.retryAfterMs}ms`);
} else {
// Unexpected error
throw error;
}
}

Validation Error Handling​

import { MemoryValidationError } from '@cortexmemory/sdk';

try {
await cortex.memory.remember({...});
} catch (error) {
if (error instanceof MemoryValidationError) {
// Instant client-side feedback
switch (error.code) {
case 'MISSING_REQUIRED_FIELD':
console.error(`Required field missing: ${error.field}`);
break;
case 'INVALID_IMPORTANCE':
console.error(`Invalid importance value for ${error.field}`);
break;
case 'OWNER_REQUIRED':
console.error('Must provide userId or agentId');
break;
default:
console.error(`Validation error: ${error.code}`);
}
}
}

Resilience Error Handling​

import {
CircuitOpenError,
QueueFullError,
RateLimitExceededError
} from '@cortexmemory/sdk';

try {
await cortex.memory.remember({...});
} catch (error) {
if (error instanceof CircuitOpenError) {
// Backend is unhealthy, retry later
const retryAfter = error.retryAfterMs || 30000;
console.log(`Circuit open, retry in ${retryAfter}ms`);
scheduleRetry(request, retryAfter);
} else if (error instanceof QueueFullError) {
// System overloaded
console.error(`Queue full for priority: ${error.priority}`);
return { status: 503, message: 'Service temporarily unavailable' };
} else if (error instanceof RateLimitExceededError) {
// Rate limit hit
console.log(`Rate limited, refill in ${error.refillInMs}ms`);
await new Promise(resolve => setTimeout(resolve, error.refillInMs));
// Retry request
}
}

Graph Error Handling​

import {
GraphConnectionError,
GraphAuthenticationError,
GraphQueryError,
} from "@cortexmemory/sdk";

// Graph sync is automatic when CORTEX_GRAPH_SYNC=true (v0.29.0+)
try {
await cortex.memory.remember({
// ... params
// No syncToGraph option needed - sync is automatic
});
} catch (error) {
if (error instanceof GraphAuthenticationError) {
console.error("Graph authentication failed");
console.error(`URI: ${error.uri}`);
console.error(`Username: ${error.username}`);
console.error("Check NEO4J_PASSWORD in .env");
} else if (error instanceof GraphConnectionError) {
console.error("Cannot connect to graph database");
// App continues working - graph is optional
} else if (error instanceof GraphQueryError) {
console.error("Graph query failed");
console.error(`Query: ${error.query}`);
}
}

Validation Errors​

Memory Validation Errors​

Class: MemoryValidationError

Source: src/memory/validators.ts

Structure:

class MemoryValidationError extends Error {
constructor(
message: string,
public readonly code: string,
public readonly field?: string,
);
}

Error Codes:

CodeFieldDescriptionFix
`MISSING_REQUIRED_FIELD``memorySpaceId`Missing or empty memorySpaceIdProvide valid memorySpaceId
`MISSING_REQUIRED_FIELD``conversationId`Missing or empty conversationIdProvide valid conversationId
`MISSING_REQUIRED_FIELD``userMessage`Missing or empty userMessageProvide message content
`MISSING_REQUIRED_FIELD``agentResponse`Missing or empty agentResponseProvide response content
`MISSING_REQUIRED_FIELD``userName`Required when userId providedProvide userName with userId
`OWNER_REQUIRED``userId/agentId`Neither userId nor agentId providedProvide at least one owner ID
`INVALID_IMPORTANCE``importance`Not between 0-100Use number 0-100
`INVALID_ID_FORMAT`(any ID field)Invalid characters in IDUse alphanumeric, hyphens, underscores
`INVALID_FORMAT``contentType`Invalid contentTypeUse "raw" or "summarized"
`INVALID_SOURCE_TYPE``sourceType`Invalid sourceType"conversation", "system", "tool", or "a2a"
`INVALID_EMBEDDING``embedding`Invalid embedding arrayProvide array of finite numbers
`INVALID_TIMESTAMP`(timestamp fields)Invalid timestampUse valid number or Date
`EMPTY_ARRAY``messageIds`Empty arrayProvide at least one element
`MISSING_CONVERSATION_REF``conversationRef`Required for conversation sourceProvide conversationRef
`INVALID_STREAM``responseStream`Invalid stream objectUse ReadableStream or AsyncIterable
`INVALID_FILTER`(filter)Insufficient filter criteriaAdd userId or sourceType filter
`INVALID_CONFIDENCE``minConfidence`Not between 0-100Use number 0-100
`INVALID_DATE_RANGE``createdAfter/createdBefore`Invalid date rangeEnsure after < before
`INVALID_GRAPH_DEPTH``graphExpansion.maxDepth`Not between 1-5Use depth 1-5
`NEGATIVE_NUMBER``limit`, `version`Negative or invalid numberUse positive integer

Example:

import { MemoryValidationError } from "@cortexmemory/sdk";

try {
await cortex.memory.remember({
conversationId: "conv-123",
userMessage: "Hello",
agentResponse: "Hi!",
userId: "user-123",
// Missing userName - will throw validation error
});
} catch (error) {
if (error instanceof MemoryValidationError) {
console.error(error.code); // "MISSING_REQUIRED_FIELD"
console.error(error.field); // "userName"
console.error(error.message); // "userName is required when userId is provided"
}
}

Conversation Validation Errors​

Class: ConversationValidationError

Source: src/conversations/validators.ts

Error Codes:

CodeFieldDescriptionFix
`MISSING_REQUIRED_FIELD`(various)Required field missingProvide required field
`INVALID_TYPE``type`Invalid conversation type"user-agent" or "agent-agent"
`INVALID_ROLE``role`Invalid message role"user", "agent", or "system"
`INVALID_ID_FORMAT``conversationId`, `messageId`Invalid ID formatRemove invalid characters
`INVALID_FORMAT``format`Invalid export format"json" or "csv"
`INVALID_SORT_ORDER``sortOrder`Invalid sort order"asc" or "desc"
`EMPTY_STRING``query`Empty search queryProvide non-empty query
`INVALID_RANGE``limit`, `offset`Invalid rangeUse valid positive integers
`EMPTY_ARRAY`(array fields)Empty arrayProvide at least one element
`INVALID_ARRAY_LENGTH`(array fields)Array length constraint violatedCheck min/max requirements
`INVALID_DATE_RANGE`(date fields)Start >= EndEnsure start < end
`INVALID_PARTICIPANTS``participants`Invalid participants structureMatch type requirements
`DUPLICATE_VALUES`(array fields)Duplicate values in arrayRemove duplicates

Facts Validation Errors​

Class: FactsValidationError

Source: src/facts/validators.ts

Error Codes:

CodeFieldDescriptionFix
`MISSING_REQUIRED_FIELD`(various)Required field missingProvide required field
`INVALID_FACT_ID_FORMAT``factId`Doesn't start with "fact-"Use "fact-" prefix
`INVALID_ARRAY`(array fields)Invalid array or elementProvide valid array
`EMPTY_ARRAY`(array fields)Empty arrayProvide at least one element
`INVALID_CONFIDENCE``confidence`Not between 0-100Use number 0-100
`INVALID_FACT_TYPE``factType`Invalid fact typeUse valid fact type
`INVALID_SOURCE_TYPE``sourceType`Invalid source typeUse valid source type
`INVALID_EXPORT_FORMAT``format`Invalid export format"json", "jsonld", or "csv"
`INVALID_SORT_BY``sortBy`Invalid sort fieldUse valid sort field
`INVALID_TAG_MATCH``tagMatch`Invalid tag match mode"any" or "all"
`INVALID_SORT_ORDER``sortOrder`Invalid sort order"asc" or "desc"
`INVALID_DATE_RANGE`(date fields)Invalid date rangeEnsure start < end
`INVALID_VALIDITY_PERIOD``validFrom`/`validUntil`Invalid validity periodEnsure validFrom < validUntil
`INVALID_UPDATE`(update fields)No fields to updateProvide at least one update field
`INVALID_CONSOLIDATION``factIds`Invalid consolidation paramsCheck requirements
`INVALID_METADATA``metadata`, `sourceRef`Invalid metadata structureProvide valid object

Valid Fact Types:

  • preference
  • identity
  • knowledge
  • relationship
  • event
  • observation
  • custom

Other Validation Errors​

User Validation Error (src/users/validators.ts)

CodeDescription
`MISSING_REQUIRED_FIELD`Required field missing
`INVALID_FORMAT`Invalid field format

Agent Validation Error (src/agents/validators.ts)

CodeDescription
`MISSING_REQUIRED_FIELD`Required field missing
`INVALID_FORMAT`Invalid field format

Session Validation Error (src/sessions/validators.ts)

CodeDescription
`MISSING_SESSION_ID`sessionId required
`INVALID_SESSION_ID`Invalid sessionId format
`INVALID_STATUS`Invalid session status
`INVALID_FILTERS`Invalid filter combination

Auth Validation Error (src/auth/validators.ts)

CodeDescription
`MISSING_AUTH_PROVIDER`Auth provider required
`MISSING_TENANT_ID`tenantId required

Resilience Errors​

Source: src/resilience/types.ts

CircuitOpenError​

Thrown when: Circuit breaker is open (backend unhealthy)

class CircuitOpenError extends Error {
constructor(
message: string = "Circuit breaker is open - request rejected",
public readonly retryAfterMs?: number,
);
}

Recovery:

  • Wait for retryAfterMs milliseconds
  • Retry the request
  • Backend will eventually recover

Example:

import { CircuitOpenError } from '@cortexmemory/sdk';

try {
await cortex.memory.remember({...});
} catch (error) {
if (error instanceof CircuitOpenError) {
const delay = error.retryAfterMs || 30000;
console.log(`Circuit open, waiting ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
// Retry
}
}

RateLimitExceededError​

Thrown when: Rate limit exceeded and waiting is disabled

class RateLimitExceededError extends Error {
constructor(
public readonly tokensAvailable: number,
public readonly refillInMs: number,
);
}

Recovery:

  • Wait for refillInMs milliseconds
  • Token bucket will refill
  • Retry the request

Example:

import { RateLimitExceededError } from '@cortexmemory/sdk';

try {
await cortex.memory.remember({...});
} catch (error) {
if (error instanceof RateLimitExceededError) {
console.log(`Rate limited, ${error.tokensAvailable} tokens available`);
console.log(`Refill in ${error.refillInMs}ms`);
await new Promise(resolve => setTimeout(resolve, error.refillInMs));
// Retry
}
}

QueueFullError​

Thrown when: Priority queue is full for the given priority

class QueueFullError extends Error {
constructor(
public readonly priority: Priority,
public readonly queueSize: number,
);
}

Recovery:

  • Reduce request volume
  • Return 503 Service Unavailable
  • Implement exponential backoff

Example:

import { QueueFullError } from '@cortexmemory/sdk';

try {
await cortex.memory.remember({...});
} catch (error) {
if (error instanceof QueueFullError) {
console.error(`Queue full for ${error.priority} priority`);
console.error(`Queue size: ${error.queueSize}`);
return { status: 503, message: 'Service overloaded' };
}
}

AcquireTimeoutError​

Thrown when: Semaphore acquire times out

class AcquireTimeoutError extends Error {
constructor(
public readonly timeoutMs: number,
public readonly waitingCount: number,
);
}

Recovery:

  • Increase timeout in resilience config
  • Reduce concurrent requests
  • Scale backend capacity

Graph Errors​

Source: src/graph/types.ts

GraphDatabaseError​

Base class for all graph errors

class GraphDatabaseError extends Error {
constructor(
message: string,
public readonly code?: string,
public readonly cause?: Error,
);
}

GraphConnectionError​

Thrown when: Connection to graph database fails

class GraphConnectionError extends GraphDatabaseError {
constructor(message: string, cause?: Error);
}

Recovery:

  • Check graph database is running
  • Verify connection URI
  • Check network connectivity

Example:

import { GraphConnectionError } from "@cortexmemory/sdk";

// Graph sync is automatic when CORTEX_GRAPH_SYNC=true (v0.29.0+)
// Graph failures are non-fatal - the app continues working
try {
await cortex.memory.remember({
// ... params
// Graph sync happens automatically if CORTEX_GRAPH_SYNC=true
});
} catch (error) {
if (error instanceof GraphConnectionError) {
console.error("Graph database unavailable");
// Graph failures are logged but don't block the operation
// The data is still stored in Convex (source of truth)
}
}

GraphAuthenticationError​

Thrown when: Graph database authentication fails

class GraphAuthenticationError extends GraphConnectionError {
constructor(
message: string,
public readonly uri: string,
public readonly username: string,
cause?: Error,
);
}

Recovery:

  • Check NEO4J_PASSWORD in .env
  • Verify username
  • Check database access permissions

Example:

import { GraphAuthenticationError } from "@cortexmemory/sdk";

try {
await graphAdapter.connect(config);
} catch (error) {
if (error instanceof GraphAuthenticationError) {
console.error("Authentication failed:");
console.error(` URI: ${error.uri}`);
console.error(` Username: ${error.username}`);
console.error("Check NEO4J_PASSWORD in .env");
// Disable graph sync by unsetting CORTEX_GRAPH_SYNC or setting to false
}
}

GraphQueryError​

Thrown when: Graph query execution fails

class GraphQueryError extends GraphDatabaseError {
constructor(
message: string,
public readonly query?: string,
cause?: Error,
);
}

Recovery:

  • Check query syntax
  • Verify node/relationship exists
  • Check database constraints

GraphNotFoundError​

Thrown when: Node or edge not found

class GraphNotFoundError extends GraphDatabaseError {
constructor(resourceType: "node" | "edge" | "path", identifier: string);
}

Other Errors​

A2ATimeoutError​

Thrown when: A2A request times out waiting for response

Source: src/types/index.ts

class A2ATimeoutError extends Error {
public readonly name = "A2ATimeoutError";

constructor(
message: string,
public readonly messageId: string,
public readonly timeout: number,
);
}

Recovery:

  • Increase timeout in A2ARequestParams
  • Check receiving agent is responding
  • Retry with exponential backoff

CascadeDeletionError​

Thrown when: User cascade deletion encounters errors

Source: src/users/index.ts

class CascadeDeletionError extends Error {
constructor(
message: string,
public readonly cause?: unknown,
);
}

Recovery:

  • Check the cause property for underlying error details
  • Retry deletion operation
  • Check permissions

AgentCascadeDeletionError​

Thrown when: Agent cascade deletion encounters errors

Source: src/agents/index.ts

class AgentCascadeDeletionError extends Error {
constructor(
message: string,
public readonly cause?: unknown,
);
}

Recovery:

  • Check the cause property for underlying error details
  • Retry deletion operation
  • Check permissions

ResumableStreamError​

Thrown when: Streaming operation fails with resume context

Source: src/memory/streaming/ErrorRecovery.ts

class ResumableStreamError extends Error {
constructor(
public readonly originalError: Error,
public readonly resumeToken: string,
);
}

Recovery:

  • Use resumeToken to resume from failure point
  • Retry with stored progress
  • Check originalError for underlying failure details

Troubleshooting Guide​

Common Errors​

"OWNER_REQUIRED"​

Cause: Neither userId nor agentId provided

Fix:

// Wrong - no owner
await cortex.memory.remember({
conversationId: "conv-123",
userMessage: "Hello",
agentResponse: "Hi",
});

// Correct - userId provided
await cortex.memory.remember({
conversationId: "conv-123",
userMessage: "Hello",
agentResponse: "Hi",
userId: "user-123",
userName: "Alex",
agentId: "assistant",
});

"MISSING_REQUIRED_FIELD: userName"​

Cause: userName required when userId is provided

Fix:

// Wrong - missing userName
await cortex.memory.remember({
conversationId: "conv-123",
userMessage: "Hello",
agentResponse: "Hi",
userId: "user-123", // userName required!
agentId: "assistant",
});

// Correct
await cortex.memory.remember({
conversationId: "conv-123",
userMessage: "Hello",
agentResponse: "Hi",
userId: "user-123",
userName: "Alex", // Added userName
agentId: "assistant",
});

"INVALID_IMPORTANCE"​

Cause: Importance not between 0-100

Fix:

// Wrong
await cortex.memory.remember({
// ... other params
importance: 150, // Out of range!
});

// Correct
await cortex.memory.remember({
// ... other params
importance: 90, // 0-100
});

"Circuit breaker is open"​

Cause: Backend is experiencing failures

Recovery Strategy:

import { CircuitOpenError } from "@cortexmemory/sdk";

async function rememberWithRetry(params, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await cortex.memory.remember(params);
} catch (error) {
if (error instanceof CircuitOpenError) {
const delay = error.retryAfterMs || 30000 * (i + 1);
console.log(`Circuit open, retry ${i + 1}/${maxRetries} in ${delay}ms`);
await new Promise((resolve) => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
throw new Error("Max retries exceeded");
}

"Queue full for priority 'normal'"​

Cause: System overloaded

Recovery Strategy:

  1. Reduce request volume:
// Use exponential backoff
const backoff = Math.min(1000 * Math.pow(2, attempt), 30000);
await new Promise((resolve) => setTimeout(resolve, backoff));
  1. Use higher priority for critical operations:
// Configure resilience with priority
const cortex = new CortexMemory({
// ... config
resilience: {
enabled: true,
// Critical operations get priority
},
});
  1. Return 503 to clients:
import { QueueFullError } from '@cortexmemory/sdk';

try {
await cortex.memory.remember({...});
} catch (error) {
if (error instanceof QueueFullError) {
return res.status(503).json({
error: 'Service temporarily unavailable',
retryAfter: 30,
});
}
}

"Graph authentication failed"​

Cause: Invalid Neo4j credentials

Fix:

  1. Check .env file:
NEO4J_URI=neo4j://localhost:7687
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=your-password-here # Check this!
CORTEX_GRAPH_SYNC=true # Enable graph sync
  1. Disable graph if credentials are unavailable:
# In .env.local - disable graph sync
CORTEX_GRAPH_SYNC=false
import { GraphAuthenticationError } from "@cortexmemory/sdk";

// Graph sync is automatic when CORTEX_GRAPH_SYNC=true (v0.29.0+)
// If graph auth fails, the operation still succeeds (graph is optional)
try {
await cortex.memory.remember({
// ... params
// Graph sync happens automatically, failures are logged but non-fatal
});
} catch (error) {
if (error instanceof GraphAuthenticationError) {
console.error("Graph auth failed - check NEO4J_PASSWORD in .env");
// Data is still stored in Convex (source of truth)
}
}

"INVALID_FACT_TYPE"​

Cause: Invalid fact type provided

Fix:

// Wrong
await cortex.facts.store({
// ... params
factType: "unknown", // Invalid!
});

// Correct - use valid fact type
await cortex.facts.store({
// ... params
factType: "preference", // Valid
});

// Valid fact types:
// - preference
// - identity
// - knowledge
// - relationship
// - event
// - observation
// - custom

Error Recovery Strategies​

Retry with Exponential Backoff​

async function withRetry<T>(
operation: () => Promise<T>,
maxRetries: number = 3,
baseDelay: number = 1000,
): Promise<T> {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
if (attempt === maxRetries - 1) {
throw error;
}

// Exponential backoff with jitter
const delay = baseDelay * Math.pow(2, attempt) + Math.random() * 1000;
console.log(`Retry ${attempt + 1}/${maxRetries} after ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error('Max retries exceeded');
}

// Usage
await withRetry(() => cortex.memory.remember({...}));

Circuit Breaker Pattern​

import { CircuitOpenError } from '@cortexmemory/sdk';

class CircuitBreakerWrapper {
private failures = 0;
private lastFailure?: number;
private readonly threshold = 5;
private readonly timeout = 60000; // 1 minute

async execute<T>(operation: () => Promise<T>): Promise<T> {
// Check if circuit should be open
if (this.failures >= this.threshold) {
const elapsed = Date.now() - (this.lastFailure || 0);
if (elapsed < this.timeout) {
throw new CircuitOpenError(
'Circuit breaker open',
this.timeout - elapsed,
);
}
// Try half-open
this.failures = this.threshold - 1;
}

try {
const result = await operation();
this.failures = 0; // Success resets failures
return result;
} catch (error) {
this.failures++;
this.lastFailure = Date.now();
throw error;
}
}
}

// Usage
const breaker = new CircuitBreakerWrapper();
await breaker.execute(() => cortex.memory.remember({...}));

Graceful Degradation​

import { GraphConnectionError, CircuitOpenError } from "@cortexmemory/sdk";

// v0.29.0+: Graph sync is automatic when CORTEX_GRAPH_SYNC=true
// Graph failures are non-fatal - data is still stored in Convex
async function rememberWithFallback(params: RememberParams) {
try {
// Graph sync happens automatically if CORTEX_GRAPH_SYNC=true
return await cortex.memory.remember({
...params,
extractFacts: true,
});
} catch (error) {
if (error instanceof GraphConnectionError) {
// Graph failures are logged but don't block the operation
console.warn("Graph unavailable - data still saved to Convex");
// The operation already succeeded for Convex
}

if (error instanceof CircuitOpenError) {
// Fallback: minimal storage
console.warn("Backend stressed, using minimal storage");
return await cortex.memory.remember({
...params,
skipLayers: ["facts", "graph"],
});
}

throw error;
}
}

See Also​