Docs K  Search
Docs/Reference/Errors
Errors

Error Handling

Learn how to handle API errors gracefully. Hebbrix uses standard HTTP status codes and returns detailed error messages to help you debug issues.

Error Response Format

All error responses follow a consistent JSON format:

Error Response
{
  "error": {
    "code": "invalid_request",
    "message": "The 'content' field is required",
    "type": "validation_error",
    "param": "content",
    "status": 400,
    "request_id": "req_abc123xyz"
  }
}
FieldTypeDescription
codestringMachine-readable error code
messagestringHuman-readable error description
typestringError category (validation_error, auth_error, etc.)
paramstring?Parameter that caused the error (if applicable)
statusintegerHTTP status code
request_idstringUnique request ID for debugging

Error response schema

There are two error envelopes you may encounter. Most application errors use a structured error object:

Standard error envelope
{
  "error": {
    "type": "...",
    "message": "...",
    "status_code": 400
  }
}

Request-validation failures raised by FastAPI (HTTP 422) use the framework's detail array instead. Each entry pinpoints the offending field:

422 Validation error
{
  "detail": [
    {
      "loc": ["body", "content"],
      "msg": "field required",
      "type": "value_error.missing"
    }
  ]
}

Common status codes

FieldTypeDescription
400statusBad request (malformed body, or a destructive-action confirmation mismatch)
401statusAuthentication failed (missing, invalid, or revoked API key)
403statusForbidden (insufficient permission, or feature not available on your tier)
404statusResource not found
422statusRequest validation failed (see the detail array)
429statusRate limited; honor Retry-After and retry
500/502/503/504statusServer or dependency failure; retry only with the same Idempotency-Key and exponential backoff, honoring Retry-After when present

Response headers & observability

Every response carries tracing headers, whether it succeeds or fails. Capture these so support can trace a request end-to-end, and so retries stay safe.

FieldTypeDescription
X-Request-IDResponseA unique UUID attached to every response (success or error). Include it when reporting an issue so it can be traced in our logs.
X-Process-TimeResponseServer processing time, in milliseconds, emitted on every response.
Idempotency-KeyRequestSend a 1–255 character opaque key on a mutating POST/PUT/PATCH/DELETE. Generic response replays are scoped to the authenticated actor and exact request fingerprint for 24 hours; canonical memory and correction keys are bound to normalized request semantics in the durable PostgreSQL outbox for that record's lifecycle.
X-Idempotent-ReplayResponseSet to true for byte-exact response-cache replays. Canonical memory and correction writes use PostgreSQL/outbox replay instead and return the same logical resource without this header.
Retry-AfterResponseOn a retryable 429, 503, or in-progress idempotency 409, the number of seconds to wait before retrying.
X-RateLimit-LimitResponseOn a 429, the request ceiling for the current window.

Idempotent retries

Attach an Idempotency-Key to any write request. Most operations retain a successful response for 24 hours, replay it byte-for-byte with X-Idempotent-Replay: true, and return 409 for a changed request fingerprint or an identical request still in progress. Canonical memory, batch, process, and correction writes use a PostgreSQL transactional-outbox contract: the same key and normalized request return the same logical resource, while readiness may advance from 202 processing to 201 completed; these logical replays do not emit X-Idempotent-Replay. A changed normalized request always returns deterministic 409, concurrent writers are serialized, and exactly one logical write commits. Failed and rate-limited response-cache operations are released for a safe same-key retry. Batch endpoints remain atomic at the durable boundary and preserve their per-item envelope; outbound webhooks carry a separate delivery key.

Idempotent retry
POST /v1/collections HTTP/1.1
Authorization: Bearer mem_sk_...
Idempotency-Key: 9f1c2b6e-7a3d-4e51-9c08-2b5d8e4a1f60
Content-Type: application/json

{"name":"Support knowledge"}

# A retry of the exact same request returns the first response:
HTTP/1.1 201 Created
X-Request-ID: 3f9a0c1d-8e2b-4a77-bd31-6c2f9e0a4b15
X-Process-Time: 0.42ms
X-Idempotent-Replay: true

Rate limiting

When you are throttled the API responds with HTTP 429, a Retry-After value (seconds) and X-RateLimit-Limit. Space your bursts and honor Retry-After. Per-request remaining-count headers on successful 2xx responses are not currently emitted, so do not rely on a remaining-count header to pace requests.

HTTP Status Codes

400 Bad Request

The request was malformed or missing required parameters.

  • Missing required fields
  • Invalid JSON body
  • Invalid parameter types

401 Unauthorized

Authentication failed or API key is invalid.

  • Missing API key
  • Invalid API key format
  • Revoked API key

403 Forbidden

The API key doesn't have permission for this action.

  • Insufficient permissions
  • Resource belongs to another user
  • Feature not available on tier

404 Not Found

The requested resource doesn't exist.

  • Invalid ID
  • Resource was deleted
  • Typo in endpoint URL

429 Too Many Requests

Rate limit exceeded. Slow down your requests.

  • Exceeded requests per minute
  • Exceeded monthly credit quota

500 Internal Server Error

Something went wrong on our end. Retry the request.

  • Temporary system issue
  • Database error

Error Codes

Common error codes returned in the error.code field:

FieldTypeDescription
invalid_api_keycodeThe API key provided is invalid or expired
missing_api_keycodeNo API key was provided in the request
invalid_requestcodeThe request body is malformed or missing fields
validation_errorcodeA parameter failed validation rules
resource_not_foundcodeThe requested resource doesn't exist
collection_not_foundcodeThe specified collection doesn't exist
rate_limit_exceededcodeToo many requests in the time window
quota_exceededcodeMonthly credit quota has been exceeded
document_too_largecodeUploaded file exceeds size limit
unsupported_formatcodeFile format is not supported
permission_deniedcodeThe API key lacks required permissions
feature_not_availablecodeFeature requires a higher tier (returned as 403; payload includes required_tier, upgrade_url, pricing_url)
internal_errorcodeAn unexpected server error occurred

403 feature_not_available payload

When a tier-gated feature is called from a tier that doesn't include it, the backend returns HTTP 403 with the structured payload below (emitted by tier_features.get_upgrade_message):

403 Feature Not Available
{
  "error": "feature_not_available",
  "feature": "knowledge_graph",
  "feature_name": "Knowledge Graph",
  "message": "Knowledge Graph requires Pro plan or higher.",
  "current_tier": {
    "name": "free",
    "display_name": "Free"
  },
  "required_tier": {
    "name": "pro",
    "display_name": "Pro",
    "price": "$99/month",
    "credits": "200K/month"
  },
  "upgrade_url": "https://app.hebbrix.com/dashboard/billing",
  "pricing_url": "https://app.hebbrix.com/pricing"
}

Handling Errors

Python

Python Error Handling
import asyncio
from hebbrix import MemoryClient
from hebbrix import (
    HebbrixError,
    AuthenticationError,
    RateLimitError,
    ValidationError,
    NotFoundError,
)

async def main():
    async with MemoryClient(api_key="mem_sk_...") as client:
        try:
            memory = await client.memories.create(
                collection_id="col_xyz",
                content="Test memory",
            )
        except AuthenticationError as e:
            # Invalid or missing API key
            print(f"Auth error: {e}")

        except RateLimitError as e:
            # Too many requests; backend returned 429
            print(f"Rate limited: {e}")

        except ValidationError as e:
            # 422: request body/params failed backend validation
            print(f"Validation error: {e}")

        except NotFoundError as e:
            # 404: the collection or memory doesn't exist
            print(f"Not found: {e}")

        except HebbrixError as e:
            # Catch-all for any other API error (5xx, etc.)
            print(f"API error: {e}")

asyncio.run(main())

TypeScript

TypeScript Error Handling
import {
  MemoryClient,
  HebbrixError,
  AuthenticationError,
  RateLimitError,
  ValidationError,
  NotFoundError,
} from 'hebbrix';

const client = new MemoryClient({ apiKey: 'mem_sk_...' });

try {
  await client.memories.create({
    collectionId: 'col_xyz',
    content: 'Test memory',
  });
} catch (error) {
  if (error instanceof AuthenticationError) {
    // Invalid or missing API key
    console.error('Auth error:', error.message);

  } else if (error instanceof RateLimitError) {
    // Too many requests
    console.error('Rate limited:', error.message);
    // Wait a bit and retry

  } else if (error instanceof ValidationError) {
    // 422: backend rejected the request body
    console.error('Validation error:', error.message);

  } else if (error instanceof NotFoundError) {
    // 404: resource doesn't exist
    console.error('Not found:', error.message);

  } else if (error instanceof HebbrixError) {
    // Catch-all for other API errors
    console.error(`API error [${error.status}]: ${error.message}`);
    console.error(`Request ID: ${error.requestId}`);

  } else {
    throw error; // Re-throw unknown errors
  }
}

Rate Limit Handling

When you hit rate limits, the response includes headers to help you retry appropriately:

429 Response
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705312800
Retry-After: 45

{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded. Please retry after 45 seconds.",
    "type": "rate_limit_error",
    "status": 429,
    "request_id": "req_xyz789"
  }
}

Implementing Exponential Backoff

Python Exponential Backoff
import asyncio
import random
from hebbrix import MemoryClient
from hebbrix import RateLimitError, HebbrixError

async def create_with_retry(client: MemoryClient, max_retries: int = 5):
    """Retry with exponential backoff + jitter on 429 / 5xx."""
    for attempt in range(max_retries):
        try:
            return await client.memories.create(
                collection_id="col_xyz", content="Test"
            )
        except RateLimitError:
            if attempt == max_retries - 1:
                raise
            sleep = (2 ** attempt) + random.uniform(0, 1)
            print(f"Rate limited, retry in {sleep:.1f}s")
            await asyncio.sleep(sleep)
        except HebbrixError:
            if attempt == max_retries - 1:
                raise
            sleep = (2 ** attempt) + random.uniform(0, 1)
            print(f"Transient error, retry in {sleep:.1f}s")
            await asyncio.sleep(sleep)


async def main():
    async with MemoryClient(api_key="mem_sk_...") as client:
        await create_with_retry(client)


asyncio.run(main())

Best Practices

  • Always Handle Errors - Wrap API calls in try/catch and handle specific error types appropriately.
  • Implement Retries - Use exponential backoff for rate limits (429) and server errors (5xx).
  • Log Request IDs - Save the request_id for debugging. Include it when contacting support.
  • Don't Expose Errors - Don't show raw API errors to end users. Display friendly messages instead.

Next Steps

Ask the docs
reading · this page

Hi! I'm the Hebbrix docs assistant. Ask me anything about this page: setup, code examples, endpoints, pricing, or integrations.