Error Handling

Nebula errors follow standard HTTP semantics and map to typed SDK exceptions so applications can decide when to fail fast and when to retry safely.

At a glance

  • Never retry 401/403 without changing credentials or permissions; treat 429/5xx as transient with jittered backoff and a cap.
  • Log the correlation/request ID from error responses for debugging while avoiding sensitive data in logs.

Common errors

StatusWhen it happensAction
400/422Invalid inputs or schema violationsFix request and do not retry until corrected; log validation details safely.
401Missing/invalid Authorization header or keyDo not retry without changing credentials; re-authenticate and reissue.
403Authenticated but insufficient permissions/scopeDo not retry; adjust key scope/permissions and try again.
404Resource or cluster not foundVerify identifiers or scope; do not blind-retry.
409Conflict (state/version)Resolve conflict or use idempotency/versioning before retry.
429Rate limitedRetry with capped exponential backoff and jitter; respect server hints if present.
5xxTransient server errorRetry with capped exponential backoff and jitter; escalate if persistent.

Exception hierarchy and HTTP mapping

ExceptionTypical HTTPMeaning
NebulaExceptionVariesBase class with status code, message, details, and request_id.
NebulaClientExceptionN/AClient/network/configuration issues before a response.
NebulaAuthenticationException401Invalid or missing authentication.
NebulaAuthorizationException403Authenticated but insufficient permissions.
NebulaRateLimitException429Rate limit exceeded; transient.
NebulaValidationException400/422Invalid parameters or payload.
NebulaNotFoundException404Resource or cluster not found.

Error payloads

Nebula error responses include a stable shape with non-sensitive context and a correlation ID for support and tracing.
{
  "error": "NebulaRateLimitException",
  "message": "Too Many Requests",
  "statusCode": 429,
  "details": { "hint": "reduce request rate" },
  "request_id": "req_12345"
}

When to retry

  • Retry 429 and 5xx with capped exponential backoff and jitter to spread retries and reduce contention.
  • Do not retry 400/401/403/404 without changing the request, credentials, or permissions; these are not transient.

Backoff with jitter

Use capped exponential backoff with full jitter; prefer idempotency for writes.
async function retryWithJitter(fn, { retries = 4, base = 300, factor = 2, cap = 5000 } = {}) {
  for (let i = 0; i < retries; i++) {
    try {
      return await fn();
    } catch (e) {
      if (i === retries - 1) throw e;
      const exp = Math.min(cap, base * Math.pow(factor, i));
      const delay = Math.random() * exp; // full jitter
      await new Promise(r => setTimeout(r, delay));
    }
  }
}

Language examples

  • Catch specific exceptions first, then fall back to the base type for a single reporting/logging path.
  • Include the request context and status code in logs, and avoid logging secrets or full payloads containing sensitive data.
from nebula_client import (
    NebulaClient,
    NebulaException,
    NebulaAuthenticationException,
    NebulaAuthorizationException,
    NebulaRateLimitException,
    NebulaValidationException,
)

client = NebulaClient(api_key="your-api-key")

try:
    memories = client.list_memories(cluster_ids=["your-cluster-id"])
except NebulaAuthenticationException as e:
    # fail fast: fix credentials/permissions
    raise
except NebulaAuthorizationException as e:
    # fail fast: adjust permissions/scope
    raise
except NebulaRateLimitException as e:
    # retry with jittered backoff (see snippet above)
    pass
except NebulaValidationException as e:
    # correct input and reissue
    pass
except NebulaException as e:
    # generic handling (e.status_code, e.message, e.details, e.request_id)
    pass

Notes on idempotency and conflicts

  • Use idempotency keys for non-idempotent writes to avoid duplicate effects when retrying.
  • Resolve 409 conflicts via versioning or by reconciling state before retrying.

Next steps