Errors
beginnerHTTP error codes, error response format, rate limiting, troubleshooting guide, and retry strategies.
Error response format
All errors return a consistent JSON structure:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "The 'text' field is required",
"status": 422,
"details": {
"field": "text",
"constraint": "required"
},
"request_id": "req_abc123def456"
}
}
| Field | Description |
|---|---|
code | Machine-readable error code (uppercase snake_case) |
message | Human-readable explanation |
status | HTTP status code |
details | Additional context (varies by error type) |
request_id | Unique identifier for support requests |
HTTP status codes
400 Bad Request
400 BAD_REQUESTThe request body is malformed or cannot be parsed.
| Code | Message | Fix |
|---|---|---|
INVALID_JSON | Request body is not valid JSON | Check JSON syntax, ensure Content-Type is application/json |
INVALID_PARAMETER | Parameter value is out of range | Check parameter constraints in the endpoint docs |
MISSING_BODY | Request body is required | Add a JSON body to the request |
401 Unauthorized
401 UNAUTHORIZEDAuthentication failed or was not provided.
| Code | Message | Fix |
|---|---|---|
MISSING_API_KEY | No API key or Bearer token provided | Add X-API-Key header or Authorization: Bearer header |
INVALID_API_KEY | API key is malformed or doesn't exist | Check key format (nx_live_ or nx_test_, 48 chars) |
EXPIRED_TOKEN | JWT access token has expired | Refresh using /v1/auth/refresh |
REVOKED_KEY | API key has been revoked | Create a new API key |
from engramma_cloud import EngrammaClient, AuthenticationError
try:
client = EngrammaClient(api_key="invalid_key")
client.stats()
except AuthenticationError as e:
print(f"Auth failed: {e.code}") # "INVALID_API_KEY"
print(f"Message: {e.message}")403 Forbidden
403 FORBIDDENAuthentication succeeded but you don't have permission for this action.
| Code | Message | Fix |
|---|---|---|
INSUFFICIENT_SCOPE | API key doesn't have the required scope | Create a key with the needed scope (e.g., memory:write) |
MEMBER_NOT_ADMIN | Action requires admin role | Ask an org admin to perform this action |
ORG_NOT_MEMBER | You're not a member of this organization | Request an invitation from an org admin |
404 Not Found
404 NOT_FOUNDThe requested resource doesn't exist.
| Code | Message | Fix |
|---|---|---|
MEMORY_NOT_FOUND | No memory with this ID exists | Verify the memory ID, it may have been deleted or consolidated |
ORG_NOT_FOUND | Organization doesn't exist | Check the org ID |
USER_NOT_FOUND | User doesn't exist | Verify the user/member ID |
ENDPOINT_NOT_FOUND | URL path doesn't match any endpoint | Check the API docs for correct paths |
409 Conflict
409 CONFLICTThe request conflicts with current state.
| Code | Message | Fix |
|---|---|---|
EMAIL_ALREADY_EXISTS | Email is already registered | Use login instead, or use a different email |
KEY_NAME_EXISTS | An API key with this name already exists | Choose a different name |
CONSOLIDATION_IN_PROGRESS | A consolidation cycle is already running | Wait for it to complete (check sleep-stats) |
422 Unprocessable Entity
422 VALIDATION_ERRORThe request is well-formed but fails validation.
| Code | Message | Fix |
|---|---|---|
VALIDATION_ERROR | Field-level validation failure | Check the details.field for which field failed |
TEXT_TOO_LONG | Text exceeds 10,000 character limit | Shorten the text or split into multiple memories |
BATCH_TOO_LARGE | Batch exceeds 100 items | Split into smaller batches |
INVALID_METADATA | Metadata exceeds size limits | Keep metadata under 10KB per memory |
PASSWORD_TOO_WEAK | Password doesn't meet requirements | Use 8+ chars with uppercase, lowercase, and number |
429 Too Many Requests
429 RATE_LIMITEDYou've exceeded your plan's rate limit.
| Code | Message | Fix |
|---|---|---|
RATE_LIMITED | Too many requests | Wait for Retry-After seconds, then retry |
BURST_EXCEEDED | Burst limit exceeded | Spread requests over a longer window |
DAILY_LIMIT_REACHED | Daily API call limit reached (Free tier) | Upgrade plan or wait until tomorrow |
Rate limit headers on 429 responses:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 50
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705312800
Retry-After: 3
from engramma_cloud import EngrammaClient, RateLimitError
import time
client = EngrammaClient(api_key=os.environ["ENGRAMMA_API_KEY"])
try:
result = client.retrieve("query")
except RateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after}s")
time.sleep(e.retry_after)
result = client.retrieve("query") # Retry
# The SDK handles retries automatically by default500 Internal Server Error
500 INTERNAL_ERRORSomething went wrong on our side.
| Code | Message | Fix |
|---|---|---|
INTERNAL_ERROR | An unexpected error occurred | Retry the request. If persistent, contact support with the request_id |
SERVICE_UNAVAILABLE | The service is temporarily down | Check status.engramma-memory.com |
Retry strategy
The SDKs implement automatic retries with exponential backoff:
| Attempt | Delay | Retries on |
|---|---|---|
| 1st retry | 1s | 429, 500, 503 |
| 2nd retry | 2s | 429, 500, 503 |
| 3rd retry | 4s | 429, 500, 503 |
| Give up | — | Returns the last error |
Never retry:
- 400 (bad request — fix the input)
- 401 (auth failed — fix credentials)
- 403 (forbidden — fix permissions)
- 404 (not found — resource doesn't exist)
- 409 (conflict — resolve the conflict)
- 422 (validation — fix the data)
# Configure retry behavior
client = EngrammaClient(
api_key=os.environ["ENGRAMMA_API_KEY"],
max_retries=3, # Default: 3
retry_delay=1.0, # Base delay in seconds
retry_backoff=2.0 # Exponential backoff multiplier
)Error handling best practices
-
Always check
error.code— not just the HTTP status. Multiple error types share the same status code. -
Log the
request_id— include it in support tickets for fast debugging. -
Handle rate limits gracefully — the
Retry-Afterheader tells you exactly how long to wait. -
Don't retry client errors — 4xx errors (except 429) won't succeed on retry.
-
Use SDK error classes — they provide typed access to error details.
When reporting issues, include the request_id from the error response. This lets support trace your exact request through the system.
Next steps
- API Overview — Base URL, auth, rate limits
- Memory Core — Core memory endpoints
- SDKs — Error handling built into the SDKs