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.

Error Hierarchy

All Synap errors inherit from SynapError. The two main branches determine retry behavior:
SynapError (base)
├── SynapTransientError (retryable — SDK auto-retries)
│   ├── NetworkTimeoutError
│   ├── RateLimitError
│   ├── ServiceUnavailableError
│   └── AgentUnavailableError
└── SynapPermanentError (non-retryable — requires code/config fix)
    ├── InvalidInputError
    │   ├── InvalidInstanceIdError
    │   └── InvalidConversationIdError
    ├── AuthenticationError
    │   ├── CertificateExpiredError
    │   ├── CertificateRenewalError
    │   └── BootstrapKeyInvalidError
    ├── BootstrapError
    ├── ContextNotFoundError
    ├── SessionExpiredError
    ├── ListeningAlreadyActiveError
    └── ListeningNotActiveError
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

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:
from synap.errors import NetworkTimeoutError

try:
    context = await sdk.conversation.context.fetch(
        conversation_id="conv_abc123",
        mode="fast"
    )
except NetworkTimeoutError as e:
    logger.warning(
        "Network timeout after all retries (correlation_id=%s)",
        e.correlation_id
    )
    # Fall back to cached context or proceed without memory
    context = None

RateLimitError

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:
from synap.errors import RateLimitError

try:
    response = await sdk.memories.create(document=doc, user_id=uid)
except RateLimitError as e:
    logger.warning(
        "Rate limited. Retry after %d seconds (correlation_id=%s)",
        e.retry_after_seconds,
        e.correlation_id
    )
    # The SDK retries automatically, but if all retries are exhausted:
    # - Queue the operation for later
    # - Reduce request frequency
    # - Consider upgrading your plan
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

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:
from synap.errors import ServiceUnavailableError

try:
    context = await sdk.conversation.context.fetch(
        conversation_id="conv_abc123",
        mode="fast"
    )
except ServiceUnavailableError as e:
    logger.error(
        "Synap Cloud unavailable (correlation_id=%s)",
        e.correlation_id
    )
    # Serve from cache if available, or degrade gracefully

Permanent Errors

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

InvalidInputError

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:
from synap.errors import InvalidInputError

try:
    response = await sdk.memories.create(
        document="",  # Empty document
        document_type="invalid-type"
    )
except InvalidInputError as e:
    logger.error("Invalid input: %s", e)
    # Fix the input data and retry

InvalidInstanceIdError

InvalidInstanceIdError
SynapPermanentError
Raised when the instance_id provided does not exist or is in an invalid format.
When it occurs:
  • The instance_id does not match the inst_<hex16> format
  • The instance has been deleted or deactivated
  • A typo in the instance ID
How to handle:
from synap.errors import InvalidInstanceIdError

try:
    await sdk.initialize()
except InvalidInstanceIdError as e:
    logger.error(
        "Invalid instance ID. Verify in the Synap Dashboard. "
        "(correlation_id=%s)", e.correlation_id
    )
    raise

InvalidConversationIdError

InvalidConversationIdError
SynapPermanentError
Raised when the conversation_id does not exist or cannot be found.
When it occurs:
  • The conversation ID references a conversation that has not been created yet
  • The conversation was deleted
  • A typo in the conversation ID
How to handle:
from synap.errors import InvalidConversationIdError

try:
    context = await sdk.conversation.context.fetch(
        conversation_id="conv_nonexistent"
    )
except InvalidConversationIdError as e:
    logger.warning("Conversation not found: %s", e)
    # Create the conversation first, or handle as a new conversation

AuthenticationError

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
  • Credentials file is corrupted or missing
  • The instance’s credentials have been rotated without updating the SDK’s stored credentials
How to handle:
from synap.errors import AuthenticationError

try:
    await sdk.initialize()
except AuthenticationError as e:
    logger.error(
        "Authentication failed: %s (correlation_id=%s)",
        e, e.correlation_id
    )
    # Re-bootstrap with a new token, or check credential files

CertificateExpiredError

CertificateExpiredError
SynapPermanentError
Raised when the mTLS certificate used for gRPC communication has expired. Certificates have a 7-day TTL with a 48-hour grace period.
When it occurs:
  • The SDK has been offline for longer than the certificate TTL (7 days) plus grace period (48 hours)
  • Certificate auto-renewal failed silently in a previous session
How to handle:
from synap.errors import CertificateExpiredError

try:
    await sdk.instance.listen(callback=on_event)
except CertificateExpiredError as e:
    logger.error("Certificate expired. Triggering re-bootstrap...")
    # Re-initialize the SDK with a new bootstrap token
    # or trigger manual certificate renewal
Under normal operation, the SDK automatically renews certificates before they expire. This error typically only occurs when the SDK has been offline for an extended period (more than 9 days).

CertificateRenewalError

CertificateRenewalError
SynapPermanentError
Raised when the SDK attempts to renew an expiring certificate but the renewal process fails.
When it occurs:
  • The certificate authority (CA) is unreachable during renewal
  • The instance’s certificate binding has been revoked
  • An internal error in the renewal process
How to handle:
from synap.errors import CertificateRenewalError

try:
    await sdk.initialize()
except CertificateRenewalError as e:
    logger.error(
        "Certificate renewal failed: %s (correlation_id=%s)",
        e, e.correlation_id
    )
    # Contact Synap support with the correlation_id
    # May require re-bootstrapping the instance

BootstrapKeyInvalidError

BootstrapKeyInvalidError
SynapPermanentError
Raised when the bootstrap token is invalid, expired, or has already been consumed.
When it occurs:
  • The bootstrap token has already been used (tokens are single-use)
  • The token has expired (bootstrap tokens have a limited validity window)
  • The token is malformed or does not correspond to the given instance
How to handle:
from synap.errors import BootstrapKeyInvalidError

try:
    await sdk.initialize()
except BootstrapKeyInvalidError as e:
    logger.error(
        "Bootstrap token is invalid or consumed. "
        "Generate a new one from the Synap Dashboard."
    )
    # Navigate to Dashboard > Instances > [instance] > Generate Bootstrap Token
Bootstrap tokens are single-use. After a successful initialize(), the token is consumed and the SDK uses persisted credentials for subsequent sessions. If you need to re-bootstrap (e.g., after deleting the ~/.synap/ directory), generate a new token from the Dashboard.

BootstrapError

BootstrapError
SynapPermanentError
Raised when the SDK fails to complete initialization — distinct from BootstrapKeyInvalidError, which is specifically about the token. BootstrapError covers broader initialization failures such as being unable to reach Synap Cloud during the bootstrap sequence.
When it occurs:
  • Synap Cloud is unreachable during the first initialize() call
  • An unexpected error occurs during the bootstrapping sequence that isn’t covered by a more specific error
How to handle:
from maximem_synap import BootstrapError

try:
    await sdk.initialize()
except BootstrapError as e:
    logger.error(
        "SDK bootstrap failed: %s (correlation_id=%s)",
        e, e.correlation_id
    )
    # Check network connectivity and Synap Cloud status, then retry

ContextNotFoundError

ContextNotFoundError
SynapPermanentError
Raised when a requested context resource does not exist — for example, fetching context for a user or conversation that has no stored memories yet.
When it occurs:
  • Fetching context for a user or conversation ID that has never ingested any memories
  • The memory was deleted before retrieval
How to handle:
from maximem_synap import ContextNotFoundError

try:
    context = await sdk.user.context.fetch(user_id="user_12345")
except ContextNotFoundError:
    logger.info("No context found for user, starting with empty state")
    context = None

SessionExpiredError

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:
from maximem_synap import SessionExpiredError

try:
    context = await sdk.conversation.context.fetch(
        conversation_id="conv_abc123"
    )
except SessionExpiredError as e:
    logger.warning(
        "Session expired (correlation_id=%s). Re-initializing...",
        e.correlation_id
    )
    await sdk.initialize()
    # Retry the operation

AgentUnavailableError

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:
from maximem_synap import AgentUnavailableError

try:
    response = await sdk.memories.create(
        document=conversation_text,
        user_id=user_id,
        customer_id=customer_id
    )
except AgentUnavailableError as e:
    logger.warning(
        "Agent unavailable after all retries (correlation_id=%s)",
        e.correlation_id
    )
    # Queue for retry later
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

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:
from maximem_synap import ListeningAlreadyActiveError

try:
    await sdk.instance.listen(callback=on_event)
except ListeningAlreadyActiveError:
    logger.warning("Listening stream already active — skipping duplicate call")
    # No action needed; the existing stream is still running

ListeningNotActiveError

ListeningNotActiveError
SynapPermanentError
Raised when you call stop_listening() or another stream operation when no listening stream is currently active.
When it occurs:
  • Calling stop_listening() before listen() has been called
  • Calling stream operations after the stream has already been stopped
How to handle:
from maximem_synap import ListeningNotActiveError

try:
    await sdk.instance.stop_listening()
except ListeningNotActiveError:
    logger.info("No active stream to stop — already inactive")
    # Safe to ignore

Using correlation_id

Every Synap error includes an optional correlation_id that uniquely identifies the failed request within Synap’s distributed tracing system.
from synap.errors import SynapError

try:
    context = await sdk.conversation.context.fetch(
        conversation_id="conv_abc123"
    )
except SynapError as e:
    logger.error(
        "Synap error: %s | correlation_id: %s | type: %s",
        str(e),
        e.correlation_id,
        type(e).__name__
    )
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.
from synap import SDKConfig, RetryPolicy

config = SDKConfig(
    retry_policy=RetryPolicy(
        max_attempts=5,               # Total attempts (1 initial + 4 retries)
        backoff_base=1.0,             # Base delay in seconds
        backoff_max=10.0,             # Maximum delay between retries
        backoff_jitter=True,          # Add random jitter to prevent thundering herd
        retryable_errors=[            # Error types to retry
            "NetworkTimeoutError",
            "RateLimitError",
            "ServiceUnavailableError"
        ]
    )
)

Retry Behavior

The SDK uses exponential backoff with optional jitter:
Attempt 1: Immediate
Attempt 2: backoff_base * 2^0 = 1.0s  (± jitter)
Attempt 3: backoff_base * 2^1 = 2.0s  (± jitter)
Attempt 4: backoff_base * 2^2 = 4.0s  (± jitter)
Attempt 5: backoff_base * 2^3 = 8.0s  (± jitter, capped at backoff_max)
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):
config = SDKConfig(retry_policy=None)

Customizing Retryable Errors

By default, only the three transient error types are retried. You can customize this list, though adding permanent errors is generally not recommended.
config = SDKConfig(
    retry_policy=RetryPolicy(
        retryable_errors=[
            "NetworkTimeoutError",
            "ServiceUnavailableError"
            # Removed RateLimitError -- handle rate limits manually
        ]
    )
)

Common Error Handling Patterns

Catch-All with Transient/Permanent Distinction

from synap.errors import (
    SynapError,
    SynapTransientError,
    SynapPermanentError,
)

try:
    response = await sdk.memories.create(
        document=conversation_text,
        user_id=user_id,
        mode="long-range"
    )
except SynapTransientError as e:
    # All retries exhausted for a transient error
    logger.warning(
        "Transient error after retries: %s (correlation_id=%s)",
        e, e.correlation_id
    )
    # Queue for retry later, or degrade gracefully
    await retry_queue.enqueue(conversation_text, user_id)

except SynapPermanentError as e:
    # Something is fundamentally wrong
    logger.error(
        "Permanent error: %s (correlation_id=%s)",
        e, e.correlation_id
    )
    # Alert, fix the issue, do not retry as-is
    raise

except SynapError as e:
    # Catch-all for any unexpected Synap error
    logger.error("Unexpected Synap error: %s", e)
    raise

Per-Operation Error Handling

from synap.errors import (
    InvalidInputError,
    InvalidConversationIdError,
    NetworkTimeoutError,
    RateLimitError,
    SynapError,
)

async def safe_fetch_context(conversation_id: str, query: str):
    """Fetch context with graceful degradation."""
    try:
        return await sdk.conversation.context.fetch(
            conversation_id=conversation_id,
            search_query=[query],
            mode="fast"
        )

    except InvalidConversationIdError:
        logger.info("No existing conversation %s, starting fresh", conversation_id)
        return None

    except NetworkTimeoutError:
        logger.warning("Timeout fetching context, proceeding without memory")
        return None

    except RateLimitError as e:
        logger.warning(
            "Rate limited, retry after %ds", e.retry_after_seconds
        )
        return None

    except SynapError as e:
        logger.error(
            "Unexpected error fetching context: %s (correlation_id=%s)",
            e, e.correlation_id
        )
        return None

Initialization Error Handling

from synap.errors import (
    BootstrapKeyInvalidError,
    AuthenticationError,
    CertificateExpiredError,
    CertificateRenewalError,
    InvalidInstanceIdError,
    NetworkTimeoutError,
    SynapError,
)

async def initialize_with_fallback():
    """Initialize SDK with comprehensive error handling."""
    try:
        await sdk.initialize()
        return True

    except BootstrapKeyInvalidError:
        logger.error("Bootstrap token consumed or invalid. Generate a new one.")
        return False

    except InvalidInstanceIdError:
        logger.error("Instance ID not found. Check your configuration.")
        return False

    except (CertificateExpiredError, CertificateRenewalError) as e:
        logger.error(
            "Certificate issue: %s. Re-bootstrap required. "
            "(correlation_id=%s)", e, e.correlation_id
        )
        return False

    except AuthenticationError as e:
        logger.error(
            "Auth failed: %s (correlation_id=%s)", e, e.correlation_id
        )
        return False

    except NetworkTimeoutError:
        logger.error("Cannot reach Synap Cloud. Check network connectivity.")
        return False

    except SynapError as e:
        logger.error(
            "Unexpected initialization error: %s (correlation_id=%s)",
            e, e.correlation_id
        )
        return False

Error Reference Table

ErrorTypeRetriedCommon CauseResolution
NetworkTimeoutErrorTransientYesNetwork issues, DNS failuresCheck connectivity; increase timeouts
RateLimitErrorTransientYesToo many requestsReduce frequency; upgrade plan
ServiceUnavailableErrorTransientYesSynap Cloud maintenanceWait and retry; check status page
AgentUnavailableErrorTransientYesAgent restarting or overloadedSDK retries automatically; queue if exhausted
InvalidInputErrorPermanentNoBad request dataFix input parameters
InvalidInstanceIdErrorPermanentNoWrong instance IDVerify in Dashboard
InvalidConversationIdErrorPermanentNoConversation not foundCheck conversation exists
AuthenticationErrorPermanentNoInvalid/revoked credentialsRe-bootstrap or check config
CertificateExpiredErrorPermanentNoSDK offline too longRe-bootstrap instance
CertificateRenewalErrorPermanentNoCA unreachable during renewalContact support
BootstrapKeyInvalidErrorPermanentNoToken consumed or expiredGenerate new token in Dashboard
BootstrapErrorPermanentNoInit failure beyond token issuesCheck connectivity; retry initialize()
ContextNotFoundErrorPermanentNoNo memories exist for resourceTreat as empty state; ingest first
SessionExpiredErrorPermanentNoSession idle or invalidatedRe-initialize SDK
ListeningAlreadyActiveErrorPermanentNolisten() called twiceSkip; existing stream still active
ListeningNotActiveErrorPermanentNostop_listening() with no streamSafe to ignore

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.