MemorySyncMemorySync
Debugging

Common Errors

Every error returned by MemorySync uses a structured JSON envelope with a machine-readable error.code, a human-readable error.message, and the request_id for tracing. This page catalogs every error status code, explains exactly when it fires, and shows you how to fix it.

Error Response Format

All error responses share a consistent outer structure. The request_id is always present — it's the first thing to grab when debugging:

{
  "error": {
    "code": "VALIDATION_ERROR",      // Machine-readable, always present
    "message": "query: Field required", // Human-readable description
    "details": [...]                    // Only on 422 responses
  },
  "request_id": "a1b2c3d4-..."        // Always present, even on 500s
}

Some older error paths use a flat format: {"error": "ValidationError", "message": "...", "request_id": "..."}. Both formats include request_id. In your error-handling code, check for error.code first, then fall back to error as a string.

400 Bad Request

A 400 response means the request was syntactically valid but semantically wrong. The platform understood your request format but rejected its content.

Error Code When It Fires Fix
ValidationErrorBusiness logic validation failed (e.g., invalid date range, conflicting parameters)Read the message field — it describes the exact constraint that was violated
INVALID_TENANT_ID_FORMATThe X-Tenant-ID header contains characters that fail format validation (injection defense)Use only alphanumeric characters and hyphens in tenant IDs
TENANT_CONTEXT_REQUIREDThe authenticated user has no default tenant and the X-Tenant-ID header was not sentAdd X-Tenant-ID: your-tenant-id to the request headers

💡 Note: The TENANT_CONTEXT_REQUIRED error is a security feature. Without an explicit tenant, the system cannot decide which tenant’s data to scope the request to, so the request is rejected rather than silently selecting the wrong tenant.

401 Unauthorized

A 401 means the system could not identify the caller. No valid credentials were found across any of the supported authentication methods.

Message Cause Fix
"API key missing"No X-API-Key header present and no Bearer token providedAdd X-API-Key: ms_... to your request headers
"Invalid API key"The key is unknown to the system or no longer in an active stateCheck the key in your dashboard → API Keys. Regenerate if needed.
"Invalid consumer token"The consumer token could not be validated against an active consumer accountRequest a fresh consumer token via the consumer auth endpoint
"Invalid or missing authentication credentials"No supported authentication method on the request resolved a valid userVerify your auth method — see the Authentication Issues page

When the 401 is for API keys, the platform records a security audit event with a short key prefix and a failure reason. These entries are visible in the audit log under the api_key category and are useful for spotting repeated failed attempts.

403 Forbidden

A 403 means the system identified the caller but the caller lacks permission for the requested operation. Unlike 401, the credentials are valid — the authorization check failed.

Message Cause Fix
"API key revoked"Key exists but has been revokedGenerate a new API key. Revoked keys cannot be reactivated.
"User account is disabled"The user's status is set to disabledContact your organization admin to re-enable the account
"User account is suspended"The user's status is set to suspendedContact your organization admin
"Admin access required"The endpoint requires admin or owner roleUse an account or API key with admin role
"Header/API key tenant mismatch"The X-Tenant-ID header doesn't match the API key's tenantRemove the X-Tenant-ID header — API key tenant is the source of truth
"Header/API key project mismatch"The X-Project-ID header doesn't match the API key's projectRemove the X-Project-ID header — API key project is the source of truth
"Not authorized for this tenant"User tried to switch to a tenant they don't have membership inVerify the user belongs to the organization that owns the target tenant
"Consumer account disabled"Consumer user status is not "active"Re-enable the consumer account via the management API

422 Validation Error

A 422 means the request body failed schema validation. The response always includes a details array with per-field error information:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "messages → 0 → content: Field required",
    "details": [
      {
        "loc": ["body", "messages", 0, "content"],
        "msg": "Field required",
        "type": "missing"
      }
    ]
  },
  "request_id": "..."
}

Reading the loc path: The location array describes the path to the invalid field. ["body", "messages", 0, "content"] means "in the request body → the messages array → first element → the content field". The "body" prefix is always present and can be ignored.

Common validation errors:

  • "Field required" — a mandatory field is missing from your request body
  • "Input should be a valid string" — wrong data type (e.g., sending a number where a string is expected)
  • "Value error, ..." — a custom business rule failed (the message after the prefix describes the rule)

💡 Tip: When the error message starts with "Value error, ", the platform strips that prefix in the top-level message field so you see the actual constraint message directly.

429 Rate Limit Exceeded

A 429 means you've exceeded one of the three rate-limit layers (per-second, per-minute, or per-hour). The response tells you exactly which layer blocked you and when to retry:

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded (per-minute). Try again in 12 seconds.",
    "limits": { "per_second": 10, "per_minute": 200, "per_hour": 5000 },
    "blocked_by": "per_minute",
    "retry_after": 12
  }
}

// Response headers:
// Retry-After: 12
// X-RateLimit-Limit: 200
// X-RateLimit-Remaining: 0
// X-RateLimit-Reset: 1715265600

How to handle in code:

  1. Read the Retry-After response header — this is the number of seconds to wait
  2. Check error.blocked_by to understand which layer is the bottleneck
  3. If blocked_by is "per_second", add a small delay between requests (you're bursting too fast)
  4. If blocked_by is "per_hour", you're hitting your budget limit — consider upgrading your plan tier

For a deep dive into rate limit tiers and response headers, see the Rate Limit Issues page.

500 Internal Server Error

A 500 is always a platform-side issue — never your fault as a caller. The response is intentionally minimal to avoid leaking internal details:

{
  "error": "InternalServerError",
  "message": "An unexpected error occurred",
  "request_id": "a1b2c3d4-e5f6-..."
}

What happens server-side: The full failure detail is recorded internally for post-mortem analysis. The request_id in the response correlates your error to that server-side record so support can investigate the exact failure.

What to do:

  • Retry once — transient infrastructure issues can cause sporadic 500s
  • Check GET /health — if a component is "unhealthy", wait for it to recover
  • Contact support — include the request_id, the endpoint, the method, and the approximate timestamp

⚠️ Important: If you're getting a 500 consistently on the same request payload, it's likely a reproducible bug. Include the full request body (with sensitive values redacted) when contacting support so the issue can be reproduced.