Errors

Typed exceptions raised by the Memco SDK.

Every failure reaching a caller is one of these. Transport and protocol failures arrive as MemcoAPIError subclasses chosen by the gRPC status code; problems with the client’s own configuration arrive as MemcoConfigError before any request is sent.

The hierarchy is arranged so a caller can be as coarse or as precise as it likes:

try:
    result = client.memory.search("how does X work", domain="coding")
except MemcoResourceExhaustedError:   # just this one condition
    ...
except MemcoAPIError:             # anything the server reported
    ...
except MemcoError:                # anything this SDK raises
    ...
exception MemcoAPIError(code, message, debug_error_string=None)[source]

Bases: MemcoError

The service returned a gRPC error status.

Prefer catching one of the subclasses. This class is useful as a catch-all for “the call reached the server and failed”, and carries the raw status for logging or for conditions the SDK does not model separately.

Variables:
  • code – The gRPC status code the server returned.

  • message – The status details string, as sent by the server. Treat this as human-readable text: it is not a stable API and should not be matched on except where this SDK already does so deliberately.

  • debug_error_string – gRPC’s internal diagnostic string, when the underlying error supplied one. Useful in bug reports; not parseable.

Parameters:
  • code (grpc.StatusCode)

  • message (str)

  • debug_error_string (str | None)

Return type:

None

exception MemcoAuthenticationError(code, message, debug_error_string=None)[source]

Bases: MemcoAPIError

The credential was missing, malformed, expired or revoked.

Never worth retrying: the same credential will be refused again. The service deliberately returns one indistinguishable message for every such case, so this exception cannot tell you which of them applied. Check that the token is current and that it is being sent as authorization: Bearer <token>.

Parameters:
  • code (grpc.StatusCode)

  • message (str)

  • debug_error_string (str | None)

Return type:

None

exception MemcoConfigError[source]

Bases: MemcoError

The client was configured incorrectly and no request was attempted.

Raised for a missing credential, an unparseable host or port, or a non-positive timeout. It never indicates a problem with the service.

Example

>>> Memco(token=None)  # with no MEMCO_API_TOKEN set
Traceback (most recent call last):
MemcoConfigError: no API token: pass token=... or set MEMCO_API_TOKEN
exception MemcoError[source]

Bases: Exception

Base class for every exception this SDK raises.

Catch this to handle any Memco failure without distinguishing a misconfigured client from a server-reported error.

exception MemcoInternalError(code, message, debug_error_string=None)[source]

Bases: MemcoAPIError

The service failed in a way it did not attribute to the request.

Also used for any status code this SDK does not model separately, so that a new server-side status can never escape as a bare grpc.RpcError. Nothing here says the call would have succeeded a moment later, so this is not the one to put a backoff loop around.

Parameters:
  • code (grpc.StatusCode)

  • message (str)

  • debug_error_string (str | None)

Return type:

None

exception MemcoInvalidRequestError(code, message, debug_error_string=None)[source]

Bases: MemcoAPIError

The request was rejected as malformed.

Never worth retrying: the same request will be refused again. Also raised by this SDK before a request is sent, when a field exceeds a documented limit or a required combination of arguments is missing. In that case code is INVALID_ARGUMENT and the message names the offending field.

Parameters:
  • code (grpc.StatusCode)

  • message (str)

  • debug_error_string (str | None)

Return type:

None

exception MemcoNotFoundError(code, message, debug_error_string=None)[source]

Bases: MemcoAPIError

A handle did not resolve to anything the caller may see.

Note

Not every “not found” condition is an error. revert_memory reports a missing operation as a successful RevertResult carrying NOT_FOUND, because that is caller-visible state rather than a service failure.

Parameters:
  • code (grpc.StatusCode)

  • message (str)

  • debug_error_string (str | None)

Return type:

None

exception MemcoPermissionError(code, message, debug_error_string=None)[source]

Bases: MemcoAPIError

The credential is valid but lacks the scope or role for this operation.

Never worth retrying: neither a retry nor a different argument changes the answer. The credential itself has to be granted what it was refused.

Parameters:
  • code (grpc.StatusCode)

  • message (str)

  • debug_error_string (str | None)

Return type:

None

exception MemcoPreconditionFailedError(code, message, debug_error_string=None)[source]

Bases: MemcoAPIError

The service refused the call because some precondition is unmet.

Never worth retrying as-is: something outside the request has to change first, so neither a retry nor a different argument gets past it. A general-purpose condition: a version past its sunset, but equally a disabled billing account, an unaccepted set of terms, or a resource in the wrong state. message names which, because only the service knows.

The one case this SDK models separately is a sunset, as MemcoSunsetError.

Parameters:
  • code (grpc.StatusCode)

  • message (str)

  • debug_error_string (str | None)

Return type:

None

exception MemcoResourceExhaustedError(code, message, debug_error_string=None)[source]

Bases: MemcoAPIError

A rate limit or a usage quota was exceeded.

Read kind before retrying: a rate limit clears on a backoff, a quota will not refill on one. The transport does not retry this on the caller’s behalf, precisely because which of the two it is decides whether retrying is worth anything, and only the caller can act on that.

Variables:

kind – Which limit was hit, inferred from the message. See ResourceExhaustedKind for why this is a heuristic and how reliable it is.

Parameters:
  • code (grpc.StatusCode)

  • message (str)

  • debug_error_string (str | None)

Return type:

None

Example

>>> try:
...     client.memory.search("...", domain="coding")
... except MemcoResourceExhaustedError as exc:
...     if exc.kind is ResourceExhaustedKind.RATE_LIMIT:
...         time.sleep(60)
...     else:
...         raise
exception MemcoSunsetError(code, message, debug_error_string, kind)[source]

Bases: MemcoPreconditionFailedError

What the caller is using is past its sunset date and is no longer served.

The end state of a deprecation: the service announced it on every ListDomains while the version still worked, and now refuses it. Nothing was done, and retrying will not help until the caller upgrades.

Both clients verify their connection before returning one, so a blocked version is refused there — in Memco’s constructor, or in connect() — rather than on the first real call.

Variables:

kind – What was blocked — this SDK build, or the API version it speaks. See SunsetKind; the two have different remedies.

Parameters:
  • code (grpc.StatusCode)

  • message (str)

  • debug_error_string (str | None)

  • kind (SunsetKind)

Return type:

None

Example

>>> try:
...     client = Memco()
... except MemcoSunsetError as exc:
...     print(exc.kind, exc.message)
exception MemcoTimeoutError(code, message, debug_error_string=None)[source]

Bases: MemcoAPIError

The call did not complete before its deadline.

The deadline is the caller’s own — the timeout on the call, else the one the client was built with — which is why the transport does not retry this: a second attempt against the same deadline has no more time than the first. Pass a larger timeout to the individual method, or to the client to raise the default for every call.

It says nothing about whether the service acted. A write that timed out may still have been recorded, so sending it again can write it twice.

Parameters:
  • code (grpc.StatusCode)

  • message (str)

  • debug_error_string (str | None)

Return type:

None

exception MemcoUnavailableError(code, message, debug_error_string=None)[source]

Bases: MemcoAPIError

The service could not be reached, or reported itself as not ready.

Covers transport failures such as a refused connection or a DNS failure, and is the base class of MemcoUnhealthyError, so catching it also catches a server that answered but declared itself unhealthy.

The one failure here a backoff is the right answer to: nothing about the request is wrong. The transport already replays it — three attempts in all — on list_domains(), get_memory() and the health probe, so seeing it from one of those means all three failed. Every other method is left alone, because replaying a write can record it twice, so retrying one of those is the caller’s decision and carries that risk.

Parameters:
  • code (grpc.StatusCode)

  • message (str)

  • debug_error_string (str | None)

Return type:

None

exception MemcoUnhealthyError(code, message, debug_error_string=None)[source]

Bases: MemcoUnavailableError

The server answered a health check but reported that it is not serving.

Distinct from a transport failure: the connection worked and the service replied, so the credential, host and TLS settings are all sound. The backend is simply not ready to take traffic. Nothing to reconfigure: wait, then construct the client again.

Parameters:
  • code (grpc.StatusCode)

  • message (str)

  • debug_error_string (str | None)

Return type:

None

class ResourceExhaustedKind(value)[source]

Bases: Enum

Which limit produced a RESOURCE_EXHAUSTED status.

The service returns the same status code for a short-window rate limit and for an exhausted usage quota, and attaches no structured error detail to separate them. This SDK therefore infers the kind from the message text.

Variables:
  • RATE_LIMIT – A short-window rate limit. Retrying after a brief pause is usually enough.

  • QUOTA – A usage quota for the billing period. Retrying will not help until the quota resets or the plan changes.

  • UNKNOWN – The message matched neither pattern. Read message to decide.

RATE_LIMIT = 'rate_limit'
QUOTA = 'quota'
UNKNOWN = 'unknown'
class SunsetKind(value)[source]

Bases: Enum

What a sunset blocked, and therefore what the remedy is.

The service reports this as a structured detail rather than leaving it to be guessed from the message, because the two have opposite remedies and telling a caller the wrong one wastes their time.

Variables:
  • CLIENT_VERSION – This build of the SDK is no longer served. Upgrade the package.

  • API_VERSION – The API version this build speaks is no longer served. Upgrading the package is what moves a caller to the current one.

CLIENT_VERSION = 'client_version'
API_VERSION = 'api_version'
from_rpc_error(err)[source]

Translate a raw grpc.RpcError into the matching SDK exception.

Every method on the client funnels failures through this function, so a caller never has to handle a bare gRPC error. An unrecognised status code becomes MemcoInternalError rather than escaping untyped.

Parameters:

err (RpcError) – The error raised by the underlying gRPC call.

Returns:

The SDK exception corresponding to the error’s status code. The result is returned rather than raised so callers can add context before raising it.

Return type:

MemcoAPIError

Example

>>> try:
...     stub.Search(request)
... except grpc.RpcError as exc:
...     raise from_rpc_error(exc) from exc