Passing exceptions back through RPC

I’m just starting with nameko but can’t seem to find docs or examples for passing exceptions back from the service to the client.

The service has a method which ultimately determines a problem. In this case, the problem is that it found more than one match for a user-provided data when the key is supposed to be unique. The user can correct this by choosing the intended key from the list of keys found, so the function throws an exception indicating the issue and includes the keys found and the user-provided data for context. Clients should catch this exception, present the user with the list of keys and a prompt to select just one. Once selected the rpc call should re-try the request.

I don’t quite know how to pass the data back on exception. The client gets a RemoteError which contains the name of the exception, but no data. I’ve tried using a worker_result dependency provider, but there isn’t a way to alter the result sent back to include the list of found keys.

Is it better to not throw an exception and instead return some kind of error state as the response? Does this mean having to return error state on each method to indicate the mode of the response?

How do others send contextualized error responses back from remote calls?

Thanks!

-Eric

The RPC entrypoint and DependencyProvider use these two functions to serialise and deserialise exceptions over the wire.

In particular the args attribute of the raised exception becomes the value attribute of the RemoteError.

You can also do a little trick to map remote exceptions to local classes:

# local_service/exceptions.py

from nameko.exceptions import registry

def remote_error(exc_path):
    """
    Decorator that registers remote exception with matching ``exc_path``
    to be deserialized to decorated exception instance, rather than
    wrapped in ``RemoteError``.
    """

    def wrapper(exc_type):
        registry[exc_path] = exc_type
        return exc_type

    return wrapper


@remote_error('remote_service.exceptions.NotFound')
class NotFound(Exception):
    pass

Now when the remote side raises remote_service.exceptions.NotFound, it will be raised on the client side as local_service.exceptions.NotFound rather than nameko.exceptions.RemoteException

Great, thank you for explaining that. I was getting tripped up in that I made some custom exceptions that took init kwargs values; when the exception materialized on the client side, the values were not set even though they were set on the server side at the time the exception was created. The serialization function you linked explains why.

The hint that helped was that ‘args’ is preserved, but kwargs set at exception creation time are not. When I realized that and then tried a @deserialize_to_instance wrapper around the exception, it all just worked.

Thanks for the help!!!

-Eric