pymediate
API Reference

Errors

API reference for validation, registration, dispatch, and service-resolution errors.

Most validation and dispatch errors inherit from PyMediateError. Service resolution uses the separate ServiceNotFoundError, which inherits from KeyError — a provider is a type-keyed mapping, so a missing service is a missing key. Subscriber failures from publish() use Python's built-in exception groups.

PyMediateError

from pymediate import PyMediateError

class PyMediateError(Exception):
    def __init__(
        self,
        message: str,
        docs_path: str | None = None,
    ): ...

docs_path is stored on the exception. When present, PyMediate appends the corresponding documentation URL to the exception message.

Definition-time errors

Handler classes are validated and registered when Python defines them, usually while importing a module. These errors indicate a class declaration that does not meet the handler contract.

InvalidHandlerSignatureError

class InvalidHandlerSignatureError(PyMediateError):
    def __init__(self, handler_type: type, issue: str): ...

Raised when a request, stream, or notification handler's __call__ has the wrong number of parameters, annotations, or synchronous/asynchronous form. Stream handlers also raise it when __call__ is not the required generator form. The handler_type and issue attributes describe the failed declaration.

InvalidRequestTypeError

class InvalidRequestTypeError(PyMediateError):
    def __init__(self, request_type: type): ...

Raised when RequestHandler[...] is parameterized with a type that has no recorded Request[ResponseT] relationship. The rejected type is available as request_type.

InvalidNotificationTypeError

class InvalidNotificationTypeError(PyMediateError):
    def __init__(self, notification_type: type): ...

Raised when NotificationHandler[...] is parameterized with a type that is not an Notification subclass. The rejected type is available as notification_type.

InvalidStreamRequestTypeError

class InvalidStreamRequestTypeError(PyMediateError):
    def __init__(self, stream_request_type: type): ...

Raised when StreamRequestHandler[...] is parameterized with a type that is not a parameterized StreamRequest subclass. The rejected type is available as stream_request_type.

ResponseTypeMismatchError

class ResponseTypeMismatchError(PyMediateError):
    def __init__(
        self,
        handler_type: type,
        expected_type: type,
        actual_type: type,
    ): ...

Raised when a request handler's return annotation differs from the response type declared by its request. It compares annotations while defining the class; PyMediate does not inspect the returned value later. The arguments are stored as handler_type, expected_type, and actual_type.

HandlerAlreadyRegisteredError

class HandlerAlreadyRegisteredError(PyMediateError):
    def __init__(
        self,
        request_type: type,
        existing_handler: type,
        new_handler: type,
        existing_location: str | None = None,
    ): ...

Raised when a second request handler or stream handler is defined for a request type already in the process-wide registry. Its attributes retain the request type, both handler classes, and the first registration location when available. Notification handlers do not use this one-handler limit.

Construction-time errors

ServiceAlreadyRegisteredError

class ServiceAlreadyRegisteredError(PyMediateError):
    def __init__(self, service_type: type): ...

Raised by Services(...) when two instances passed to one construction share a concrete type. A collection holds one instance per exact type, so only the first could ever be resolved — a repeat is a wiring mistake rather than a preference. The repeated type is stored as service_type. Use left | right to replace a service deliberately; the right operand wins and a shared type is not an error there.

InvalidPipelineBehaviorsError

class InvalidPipelineBehaviorsError(PyMediateError):
    def __init__(self, entry: object, issue: str): ...

Mediator(services, behaviors=[...]) validates the behaviors sequence once, when the mediator is constructed. Raised when an entry is not a PipelineBehavior subclass of the mediator's variant, is not registered with services, or is listed more than once. The offending entry and a description of the failed check are stored as entry and issue.

Dispatch-time errors

HandlerNotFoundError

class HandlerNotFoundError(PyMediateError):
    def __init__(
        self,
        request_type: type,
        available_handlers: list[type] | None = None,
    ): ...

Mediator.send() and Mediator.stream() raise this error when the exact request class has no registered handler class. The attributes are request_type and available_handlers. A missing handler instance is instead a service-resolution error.

ServiceNotFoundError

class ServiceNotFoundError(KeyError):
    def __init__(
        self,
        service_type: type,
        available_types: list[type],
    ) -> None: ...

ServiceProvider.__getitem__ raises this error when no instance is registered for the exact requested type. During mediator dispatch, that can occur while resolving a request handler, stream handler, or notification handler. The arguments are stored as service_type and available_types.

It subclasses KeyError, mirroring the subscript that raises it (provider[service_type]), so a missing service can be caught with except KeyError. str(error) still renders the full multi-line message rather than KeyError's repr-wrapped form.

Because ServiceNotFoundError is not a PyMediateError, catching PyMediateError alone does not catch all mediator configuration failures.

Other propagated failures

  • send() lets handler and pipeline-behavior exceptions propagate unchanged.
  • stream() lets generator-body exceptions propagate during iteration.
  • Asynchronous publish() aggregates ordinary subscriber failures in an ExceptionGroup. Other collected BaseException values produce a BaseExceptionGroup; KeyboardInterrupt and SystemExit propagate directly and can cancel unfinished subscribers.
  • Synchronous publish() aggregates ordinary subscriber exceptions in an ExceptionGroup. A direct BaseException that is not an Exception stops delivery and propagates immediately.

See also

On this page