diff --git a/net/include/ftl/net/protocol.hpp b/net/include/ftl/net/protocol.hpp
index fc4925e29bd911095989cdd92f38da07da96a425..8679bb4a27d2f90c9c846124e9f9737efd06d4b8 100644
--- a/net/include/ftl/net/protocol.hpp
+++ b/net/include/ftl/net/protocol.hpp
@@ -69,7 +69,7 @@ class Protocol {
 	
 	static Protocol *find(const std::string &id);
 			
-	protected:
+	//protected:
 	void dispatchRPC(Socket &, const std::string &d);
 	void dispatchReturn(Socket &, const std::string &d);
 	void dispatchRaw(uint32_t service, Socket &);
diff --git a/net/src/dispatcher.cpp b/net/src/dispatcher.cpp
index 8bbe3a1b44a76e5d43f37924cd38d3179fcfd5f7..32239bd2b52dd31d1238aaea43091f5fa1d8bcf2 100644
--- a/net/src/dispatcher.cpp
+++ b/net/src/dispatcher.cpp
@@ -55,14 +55,22 @@ void ftl::net::Dispatcher::dispatch_call(Socket &s, const msgpack::object &msg)
             auto result = (it_func->second)(args); //->get();
             response_t res_obj = std::make_tuple(1,id,msgpack::object(),result->get());
 			std::stringstream buf;
-			msgpack::pack(buf, res_obj);
-			
-			//std::cout << " RESULT " << result.as<std::string>() << std::endl;
-			
+			msgpack::pack(buf, res_obj);			
 			s.send(FTL_PROTOCOL_RPCRETURN, buf.str());
-        } catch (int e) {
+		} catch (const std::exception &e) {
+			//throw;
+			//LOG(ERROR) << "Exception when attempting to call RPC (" << e << ")";
+            response_t res_obj = std::make_tuple(1,id,msgpack::object(e.what()),msgpack::object());
+			std::stringstream buf;
+			msgpack::pack(buf, res_obj);			
+			s.send(FTL_PROTOCOL_RPCRETURN, buf.str());
+		} catch (int e) {
 			//throw;
-			LOG(ERROR) << "Exception when attempting to call RPC (" << e << ")";
+			//LOG(ERROR) << "Exception when attempting to call RPC (" << e << ")";
+            response_t res_obj = std::make_tuple(1,id,msgpack::object(e),msgpack::object());
+			std::stringstream buf;
+			msgpack::pack(buf, res_obj);			
+			s.send(FTL_PROTOCOL_RPCRETURN, buf.str());
 		}
     }
 }
diff --git a/net/src/net.cpp b/net/src/net.cpp
index 0d2943f917a34e6c77a16fab0f00ef23ebf75a6a..1ef7a8d368a49c142111b2a9728cbd459e60d9d2 100644
--- a/net/src/net.cpp
+++ b/net/src/net.cpp
@@ -11,7 +11,7 @@ using namespace std::chrono;
 using ftl::net::Listener;
 using ftl::net::Socket;
 
-static std::vector<shared_ptr<ftl::net::Socket>> sockets;
+ std::vector<shared_ptr<ftl::net::Socket>> sockets;
 static std::vector<shared_ptr<ftl::net::Listener>> listeners;
 static fd_set sfdread;
 static fd_set sfderror;
diff --git a/net/test/protocol_unit.cpp b/net/test/protocol_unit.cpp
index 65fca0b0ef6b62354b8e0611553615d00737d1a0..48773176b09e6ed2c56b1be44d352a2e38c629cd 100644
--- a/net/test/protocol_unit.cpp
+++ b/net/test/protocol_unit.cpp
@@ -1,18 +1,22 @@
 #include "catch.hpp"
 #include <ftl/net/protocol.hpp>
+#include <ftl/net/dispatcher.hpp>
 
 using ftl::net::Protocol;
+using ftl::net::Dispatcher;
 
 // --- Mock --------------------------------------------------------------------
 
 #define _FTL_NET_SOCKET_HPP_ // Prevent include
 
+static std::string last_send;
+
 namespace ftl {
 namespace net {
 class Socket {
 	public:
 	std::string getURI() { return "mock://"; }
-	int send(int msg, const std::string &d) { return 0; }
+	int send(int msg, const std::string &d) { last_send = d; return 0; }
 };
 };
 };
@@ -29,6 +33,13 @@ class MockProtocol : public Protocol {
 
 // --- Support -----------------------------------------------------------------
 
+Dispatcher::response_t get_response() {
+	auto unpacked = msgpack::unpack(last_send.data(), last_send.size());
+	Dispatcher::response_t the_result;
+	unpacked.get().convert(the_result);
+	return the_result;
+}
+
 // --- Files to test -----------------------------------------------------------
 
 #include "../src/protocol.cpp"
@@ -64,11 +75,11 @@ TEST_CASE("Protocol::bind(int,...)", "[proto]") {
 	}
 }
 
-TEST_CASE("Protocol::bind(string,...)", "[proto]") {
+SCENARIO("Protocol::bind(string,...)", "[proto]") {
 	MockProtocol p;
 	Socket s;
 	
-	SECTION("no argument bind with valid dispatch") {
+	GIVEN("no arguments and no return") {
 		bool called = false;
 		
 		p.bind("test1", [&]() {
@@ -84,7 +95,7 @@ TEST_CASE("Protocol::bind(string,...)", "[proto]") {
 		REQUIRE( called );
 	}
 	
-	SECTION("multiple bindings") {
+	GIVEN("multiple no argument bindings") {
 		bool called1 = false;
 		bool called2 = false;
 		
@@ -105,7 +116,7 @@ TEST_CASE("Protocol::bind(string,...)", "[proto]") {
 		REQUIRE( called2 );
 	}
 	
-	SECTION("one argument bind with valid dispatch") {
+	GIVEN("one argument") {
 		bool called = false;
 		
 		p.bind("test1", [&](int a) {
@@ -122,7 +133,7 @@ TEST_CASE("Protocol::bind(string,...)", "[proto]") {
 		REQUIRE( called );
 	}
 	
-	SECTION("two argument bind fake dispatch") {
+	GIVEN("two arguments no return") {
 		bool called = false;
 		
 		p.bind("test1", [&](int a, float b) {
@@ -140,7 +151,7 @@ TEST_CASE("Protocol::bind(string,...)", "[proto]") {
 		REQUIRE( called );
 	}
 	
-	SECTION("non-void bind no arguments") {
+	GIVEN("integer return, no arguments") {
 		bool called = false;
 		
 		p.bind("test1", [&]() -> int {
@@ -156,7 +167,85 @@ TEST_CASE("Protocol::bind(string,...)", "[proto]") {
 		p.mock_dispatchRPC(s, buf.str());
 		REQUIRE( called );
 		
-		// TODO Require that a writev occurred with result value
+		auto [kind,id,err,res] = get_response();
+		REQUIRE( res.as<int>() == 55 );
+		REQUIRE( kind == 1 );
+		REQUIRE( id == 0 );
+		REQUIRE( err.type == 0 );
+	}
+	
+	GIVEN("integer return and one argument") {
+		bool called = false;
+		
+		p.bind("test1", [&](int a) -> int {
+			called = true;
+			return a+2;
+		});
+		
+		auto args_obj = std::make_tuple(12);
+		auto call_obj = std::make_tuple(0,0,"test1",args_obj);
+		std::stringstream buf;
+		msgpack::pack(buf, call_obj);
+		
+		p.mock_dispatchRPC(s, buf.str());
+		REQUIRE( called );
+		
+		auto [kind,id,err,res] = get_response();
+		REQUIRE( res.as<int>() == 14 );
+		REQUIRE( kind == 1 );
+		REQUIRE( id == 0 );
+		REQUIRE( err.type == 0 );
+	}
+	
+	GIVEN("an integer exception in bound function") {
+		bool called = false;
+		
+		p.bind("test1", [&](int a) {
+			called = true;
+			throw -1;
+		});
+		
+		auto args_obj = std::make_tuple(5);
+		auto call_obj = std::make_tuple(0,0,"test1",args_obj);
+		std::stringstream buf;
+		msgpack::pack(buf, call_obj);
+		
+		p.mock_dispatchRPC(s, buf.str());
+		REQUIRE( called );
+		
+		auto [kind,id,err,res] = get_response();
+		REQUIRE( res.type == 0 );
+		REQUIRE( kind == 1 );
+		REQUIRE( id == 0 );
+		REQUIRE( err.as<int>() == -1 );
+	}
+	
+	GIVEN("a custom std::exception in bound function") {
+		bool called = false;
+		
+		struct CustExcept : public std::exception {
+			const char *what() const noexcept { return "My exception"; }
+		};
+		
+		p.bind("test1", [&](int a) {
+			called = true;
+			throw CustExcept();
+		});
+		
+		auto args_obj = std::make_tuple(5);
+		auto call_obj = std::make_tuple(0,0,"test1",args_obj);
+		std::stringstream buf;
+		msgpack::pack(buf, call_obj);
+		
+		p.mock_dispatchRPC(s, buf.str());
+		REQUIRE( called );
+		
+		auto [kind,id,err,res] = get_response();
+		REQUIRE( res.type == 0 );
+		REQUIRE( kind == 1 );
+		REQUIRE( id == 0 );
+		REQUIRE( err.type == 5 );
+		REQUIRE( err.as<std::string>() == "My exception" );
 	}
 }