Error Handling
Uncaught Errors
Any error parsing a JSON-RPC request or any error that occurs executing a function will be wrapped in a JSON-RPC Error Object.
By default, the error returned will be a generic server error. The following:
from openrpc import RPCApp
rpc = RPCApp()
@rpc.method()
def divide(a: int, b: int) -> float:
return a / b
req = '{"id": 1, "method": "divide", "params": {"a": 2, "b": 0}, "jsonrpc": "2.0"}'
print(await rpc.process(req))
Produces this error response:
{
"id": 1,
"error": {
"code": -32000,
"message": "Server error"
},
"jsonrpc": "2.0"
}
Debug
In order to include stack trace in the error response set debug=True for the RPCApp.
rpc = RPCApp()
Now the error response will contain error details in the data.
{
"id": 1,
"error": {
"code": -32000,
"message": "Server error",
"data": "ZeroDivisionError: division by zero\n File \"/home/matthew/Projects/openrpc-app/app.py\", line 8, in divide\n return a / b\nZeroDivisionError: division by zero\n"
},
"jsonrpc": "2.0"
}
Custom Errors
You will likely want errors that preserve the error code and message.
For that, create and error class that extends OpenRPCError.
from openrpc import OpenRPCError, RPCApp
rpc = RPCApp()
class CustomError(OpenRPCError):
"""Error that will preserve custom code, message, and data."""
def __init__(self, a: int, b: int, *args: object) -> None:
"""Instantiate custom error."""
self.message = "Custom RPC error."
self.code = -32002
self.data = {"a": a, "b": b}
super().__init__(self.code, self.message, self.data, *args)
@rpc.method()
def divide(a: int, b: int) -> float:
"""Divide two numbers."""
try:
return a / b
except ZeroDivisionError as e:
raise CustomError(a, b) from e
req = '{"id": 1, "method": "divide", "params": {"a": 2, "b": 0}, "jsonrpc": "2.0"}'
print(await rpc.process(req))
Now error details are preserved.
{
"id": 1,
"error": {
"code": -32002,
"message": "Custom RPC error.",
"data": {
"a": 2,
"b": 0
}
},
"jsonrpc": "2.0"
}