Troubleshooting
Identify installation, handler registration, service wiring, and type-checking problems.
PyMediate errors distinguish handler class registration from handler instance resolution. Check which stage failed before changing the service configuration.
Dispatch errors
| Error | Meaning | First check |
|---|---|---|
HandlerNotFoundError | No handler class is registered for the exact request type | Was the module that defines the handler imported? |
ServiceNotFoundError | A handler class is registered, but the provider cannot supply its instance | Was the instance added before Services? |
HandlerAlreadyRegisteredError | A second request or stream handler class was defined for one request type | Search for both class definitions or duplicate imports |
ExceptionGroup from publish() | One or more notification handlers raised | Inspect the grouped exceptions with except* |
HandlerNotFoundError
Request and stream handler classes register when Python defines them. The mediator raises
HandlerNotFoundError when its registry has no handler class for the concrete request type.
Check that:
- the module containing the handler has been imported before dispatch;
- the handler's type argument names the request you are sending;
- you are using
send()forRequestandstream()forStreamRequest; and - you are not sending a derived request while only its base request has a handler.
Dispatch uses type(request), not isinstance(). A handler for a base request does not
receive a derived request.
Adding an instance to Services does not create the request-to-handler class mapping. That
mapping comes from defining RequestHandler[RequestType] or
StreamRequestHandler[RequestType]. Conversely, once a mapping exists, a missing instance
raises ServiceNotFoundError, not HandlerNotFoundError.
ServiceNotFoundError
Pass every handler instance to Services(...) and hand that collection to Mediator.
Resolution is by exact type, so a handler registered as a subclass does not satisfy a request
for its base class. With DependencyInjectorServiceProvider, check that the container declares
a provider whose resolved type is the exact handler class.
Publishing resolves every subscriber instance before any handler runs. One missing notification
handler instance therefore raises ServiceNotFoundError and prevents partial delivery.
HandlerAlreadyRegisteredError
Each Request or StreamRequest type has one handler class in a process. Defining a second
class for the same request type raises this error immediately, before either handler is
instantiated.
Common causes are:
- two implementations for one request type;
- a test suite that defines replacement handler classes in several files;
- importing the same source module under two module names; or
- defining asynchronous and synchronous handlers for the same request type.
Keep one handler class and vary its dependencies through the constructor. Use distinct
request types when the operations have different contracts. Notification handlers are different:
several NotificationHandler classes may subscribe to one notification type.
Construction errors
ServiceAlreadyRegisteredError
Services(...) received two instances of the same concrete type. Only one instance per exact type
is resolvable, so the second could never be reached.
Check that:
- no handler or behavior instance is passed twice — a
Services(*handlers, *behaviors)call can repeat one if a class appears in both lists; and - two distinct services really do have distinct types. Two instances of one class configured differently cannot both be resolved; give them separate classes if both must be.
To replace a service on purpose — swapping a fake into a production wiring for a test — combine
two collections with | instead. The right operand wins, and a shared type is not an error there.
InvalidPipelineBehaviorsError
Mediator(services, behaviors=[...]) validates the behaviors sequence once, at construction.
Each entry must be a PipelineBehavior subclass of the mediator's variant (asynchronous for
pymediate.Mediator, synchronous for pymediate.sync.Mediator), registered with services, and
listed at most once.
Check that:
- every class in
behaviorswas added toServices(or the container behind your custom provider) before building the provider; behaviorsmixes only classes from the mediator's own variant - an asynchronous behavior in a synchronous mediator'sbehaviorslist, or vice versa, fails the subclass check; and- no class appears twice in the list.
A behavior registered with the provider but left out of behaviors does not raise - it is simply
not part of the pipeline. If a behavior you expect to run does not, check behaviors first before
suspecting should_apply().
Definition-time validation errors
PyMediate validates handler declarations when Python executes their class bodies. An error
at import time usually means the declaration and __call__ signature disagree.
InvalidHandlerSignatureError
For a request handler, check all of the following:
__call__has onlyselfand one request parameter;- the request parameter and return value both have annotations;
- the parameter annotation is the exact type named in
RequestHandler[...]; - the asynchronous class uses
async def, while the synchronous class usesdef; and - a notification handler returns
None.
Stream handlers must be generators. Their return annotation must be
AsyncIterator[ChunkT] for the asynchronous API or Iterator[ChunkT] for the synchronous
API. Returning an iterator from a function that contains no yield is rejected.
ResponseTypeMismatchError
The return annotation on a request handler must equal the response type declared by its
request. For example, a handler for PlaceOrder, where
PlaceOrder(Request[OrderReceipt]), must annotate its return as OrderReceipt.
This check compares annotations when Python defines the handler class. PyMediate does not inspect the value returned on every call. Keep a static type checker enabled so an implementation that returns a value inconsistent with its annotation is also reported.
Invalid request, notification, or stream types
InvalidRequestTypeErrormeans a request handler's type argument does not declare a response throughRequest[ResponseT].InvalidNotificationTypeErrormeans a notification handler's type argument does not inheritNotification.InvalidStreamRequestTypeErrormeans a stream handler's type argument does not declare a chunk type throughStreamRequest[ChunkT].
These constraints are also represented in the type annotations, so mypy and pyright can report many of them before import-time validation runs.
Type inference problems
If mediator.send() is inferred as returning Any, check that the concrete request
parameterizes Request:
from dataclasses import dataclass
from pymediate import Request
@dataclass(frozen=True)
class OrderReceipt:
order_id: int
summary: str
@dataclass(frozen=True)
class PlaceOrder(Request[OrderReceipt]):
customer_id: int
item: str
quantity: intA bare Request loses the relationship between the request and response types. Similarly, a
bare StreamRequest loses the stream's chunk type. See type safety
for the boundary between static checking and definition-time validation.
Installation problems
PyMediate requires Python 3.12 or newer. Check that the interpreter used to run the application is the same environment in which the package was installed.
DependencyInjectorServiceProvider requires the optional di extra:
pip install 'pymediate[di]'Getting help
- Check the guide and API reference.
- Search existing issues.
- Ask in GitHub Discussions.
- Report a reproducible bug.