Skip to main content

Overview

The Synap SDK uses a structured error hierarchy to distinguish between transient errors (which are automatically retried) and permanent errors (which require your intervention). Understanding this hierarchy is essential for building robust integrations. This page is the handling guide: the hierarchy, when each error fires, and the try/except patterns to catch them.

Full error reference →

For the exhaustive catalog of server-side error codes (the wire-level code field, HTTP status, and details shape) see Error Codes. For the complete SDK exception table at a glance, see SDK Reference: Error handling.

Error Hierarchy

All Synap errors inherit from SynapError. The two main branches determine retry behavior:
All errors include an optional correlation_id field that uniquely identifies the request. This ID is invaluable for debugging and when contacting Synap support.
The hierarchy below reflects the full public error surface. AgentUnavailableError is transient (retryable); all others under SynapPermanentError are non-retryable.

Transient Errors

Transient errors represent temporary conditions that typically resolve on their own. The SDK automatically retries these errors according to your configured retry policy. You only need to handle them if all retry attempts are exhausted.

NetworkTimeoutError

SynapTransientError
Raised when a network request to Synap Cloud times out before completing.
When it occurs:
  • Network connectivity issues between your application and Synap Cloud
  • DNS resolution failures
  • The request exceeded the configured connect or read timeout
How to handle:
conversation_id must be a valid UUID string; non-UUID values are rejected by the server. Generate one with str(uuid.uuid4()), or reuse the UUID you already manage per conversation. The examples below use str(uuid.uuid4()) to make this explicit.

RateLimitError

SynapTransientError
Raised when your application exceeds the rate limit for the Synap API. Includes a retry_after_seconds field indicating how long to wait before retrying.
When it occurs:
  • Too many requests in a short time window
  • Burst traffic exceeding your plan’s rate limit
How to handle:
The SDK’s built-in retry policy respects retry_after_seconds automatically. If the rate limit is short (a few seconds), the SDK waits and retries without raising the error to your code. The error only surfaces when all retry attempts are exhausted.

ServiceUnavailableError

SynapTransientError
Raised when Synap Cloud is temporarily unavailable due to maintenance, deployment, or an outage.
When it occurs:
  • Synap Cloud is undergoing maintenance
  • A rolling deployment is in progress
  • Temporary backend issues
How to handle:

Permanent Errors

Permanent errors indicate problems that will not resolve by retrying. They require changes to your code, configuration, or data.

InvalidInputError

SynapPermanentError
Raised when the request contains invalid parameters or data that fails validation.
When it occurs:
  • Invalid document_type value
  • Missing required fields
  • Parameter values outside valid ranges
  • Malformed data in the request body
How to handle:

InvalidInstanceIdError

InvalidInputError
A defined subtype of InvalidInputError for an unknown or malformed instance_id.
A malformed instance_id is rejected by the SDK itself, and raised from the constructor before any request is made: you do not reach initialize(). An id that is well-formed but unknown to the server is a different case: it comes back as an HTTP 400 and surfaces as the base InvalidInputError. Catching InvalidInputError handles both, since this is a subtype of it.
When it occurs:
  • The instance_id does not match the expected format: inst_ followed by 16 hex characters, e.g. inst_a1b2c3d4e5f67890. Raised by MaximemSynapSDK(...) itself; an empty value is left alone, since the instance is normally resolved from the API key during initialize().
  • The instance has been deleted or deactivated (server-side, surfaces as InvalidInputError)
  • A typo in the instance ID
How to handle:
Passing instance_id is optional, and usually unnecessary: the API key already identifies its instance and the SDK resolves it during initialize(). Omitting it avoids this error class entirely.

InvalidConversationIdError

InvalidInputError
A defined subtype of InvalidInputError for a malformed conversation_id (for example, a non-UUID string).
The SDK currently surfaces a malformed conversation_id as the base InvalidInputError (HTTP 400), not as this specific subtype. Catch InvalidInputError. Note that a well-formed conversation_id with no messages yet does not raise; it returns an empty ContextResponse (see cold-start behavior).
When it occurs:
  • The conversation_id is not a valid UUID
  • A typo or wrong identifier format
How to handle:

AuthenticationError

SynapPermanentError
Raised when the SDK cannot authenticate with Synap Cloud. This is a general authentication failure.
When it occurs:
  • API key is invalid or revoked
  • No API key was provided (neither SYNAP_API_KEY env var nor the api_key= constructor argument)
  • The instance’s credentials have been rotated without updating the API key your application uses
How to handle:

ContextNotFoundError

SynapPermanentError
Raised when a requested context resource genuinely cannot be located, distinct from a valid resource that simply has no memories yet, which returns an empty ContextResponse rather than raising.
Empty result vs. raised error, which happens per method:
  • sdk.conversation.context.fetch(): a brand-new or never-ingested conversation_id returns an empty ContextResponse (facts == [], preferences == [], etc.), not an error. This is the normal cold-start path. A malformed (non-UUID) conversation_id raises InvalidInputError instead.
  • sdk.user.context.fetch() / sdk.customer.context.fetch() / sdk.client.context.fetch(): a scope that has never had memories ingested also returns an empty ContextResponse. Treat empty lists as “no context yet,” not as an error.
ContextNotFoundError is reserved for the case where the underlying context resource itself is missing or was removed, not for the everyday “new conversation / new user” case. When it occurs:
  • A previously available context resource was deleted before retrieval
  • The backend cannot locate the addressed context resource (as opposed to locating it and finding it empty)
How to handle:

SessionExpiredError

SynapPermanentError
Raised when the current session has expired and cannot be resumed. Sessions are time-bounded and must be re-established after expiry.
When it occurs:
  • The session has been idle beyond its expiry window
  • The session was invalidated server-side (e.g., credential rotation)
How to handle:

InsufficientCreditsError

SynapPermanentError
Raised when the client’s credit balance is too low to satisfy the request. Carries balance_credits, minimum_required_credits, recovery_url, and redeem_url so you can surface the right next-step to the user. See Pricing & Credits for how credits and overage work.
When it occurs:
  • The client has run out of credits
  • The current credit balance is below the minimum required for the requested operation
How to handle:

AgentUnavailableError

SynapTransientError
Raised when the Synap agent backing the instance is temporarily unavailable. This is a transient error; the SDK will automatically retry.
When it occurs:
  • The agent process is restarting or being redeployed
  • Temporary resource contention on the backend
How to handle:
The SDK automatically retries AgentUnavailableError according to your configured retry policy. This error only surfaces to your code when all retry attempts are exhausted.

ListeningAlreadyActiveError

SynapPermanentError
Raised when you call listen() on an instance that already has an active listening stream. Only one stream can be active per SDK instance at a time.
When it occurs:
  • Calling listen() a second time without first calling stop_listening()
  • Duplicate initialization paths in your application
How to handle:

ListeningNotActiveError

SynapPermanentError
Raised by send_message() when no listening stream is currently active.
When it occurs:
  • Calling send_message() before listen() has been called
  • Calling send_message() after stop_listening(), or while the stream is down and has not yet reconnected
stop_listening() does not raise this. It is idempotent and a safe no-op when no stream is active, so it needs no guard.
How to handle:
In a long-lived server, guard with if sdk.instance.is_listening: rather than catching per call. That is what the framework integrations do: stream sends log and never raise.

Stream health

The Listen stream fails in a way that is deliberately invisible to your application, so it needs different handling from the errors above.
A permanently dead stream is silent: retrieval still returns correct results, just slower. Do not infer stream health from your agent working. Export sdk.instance.is_listening to your health endpoint and alert when it stays false. See Real-Time Anticipation in a Server.

Using correlation_id

Every Synap error includes an optional correlation_id that uniquely identifies the failed request within Synap’s distributed tracing system.
Always log the correlation_id from errors. Synap support can use it to trace the exact request path through the backend, including which pipeline stages were involved, what data was processed, and where the failure occurred.

Retry Policy Configuration

The SDK’s built-in retry policy handles transient errors automatically. You can customize the retry behavior through RetryPolicy in your SDKConfig.
JavaScript decides this differently, on purpose. There is no retryable_errors list: every transient error is retried, and a non-idempotent call whose outcome is unknown is not, whatever its type. That second rule is what stops a lost response on memories.create from ingesting and billing the same content twice, and a per-error list could switch it off. To handle rate limits yourself, catch RateLimitError at the call site.

Retry Behavior

The SDK uses exponential backoff with optional jitter:
For RateLimitError, the SDK respects the retry_after_seconds value instead of the exponential backoff, waiting the exact duration specified by the server.

Disabling Retries

To disable automatic retries entirely (useful for testing or when you implement your own retry logic):

Customizing Retryable Errors

By default, all four transient error types are retried (NetworkTimeoutError, RateLimitError, ServiceUnavailableError, and AgentUnavailableError). Listing the base SynapTransientError in retryable_errors covers every transient subtype, including any added in future SDK releases. You can customize this list, though adding permanent errors is generally not recommended.
Python only, deliberately. JavaScript retries every transient error and never a non-idempotent call whose outcome is unknown. Narrowing that by error type could re-enable a retry that ingests and bills the same content twice, so the list is not offered. Catch RateLimitError at the call site instead.

Common Error Handling Patterns

Catch-All with Transient/Permanent Distinction

Per-Operation Error Handling

Initialization Error Handling

Full error reference

The hierarchy and handling patterns above cover how to catch and respond to each error. For the at-a-glance catalog (every SDK exception class with its transient/permanent type and common cause) see SDK Reference: Error handling. For the server-side wire codes those exceptions wrap (HTTP status, machine-readable code, and details shape) see Error Codes.

Next Steps

SDK Configuration

Customize retry policies, timeouts, and other SDK settings.

Initializing the SDK

Set up the SDK with proper error handling from the start.

Support

Contact Synap support with correlation IDs for issue resolution.

FAQ

Common questions about errors and troubleshooting.

JavaScript: typed error handling

Error classes are real classes, so instanceof narrowing works, and each carries a stable .code and a .transient flag:
Transient errors are retried automatically. Ingestion is deliberately not retried when a failure leaves the outcome unknown, because a retry would store and bill twice.