diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f0028d08b1bb00e15c09ce7cbec2b18955d4b725..18784fd0bac25eb23ab6d2c852d270f01cebf303 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -42,9 +42,25 @@ add_custom_target(ragel
     WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
     COMMAND ragel -G2 src/uri.rl -o src/uri.c)
 
-set (common_sources
+set (core_sources
+     say.cc
      memory.cc
      fiber.cc
+     exception.cc
+     coro.cc
+     object.cc
+     assoc.c
+ )
+
+add_library(core STATIC ${core_sources})
+target_link_libraries(core
+    salad small
+    ${LIBEV_LIBRARIES}
+    ${LIBEIO_LIBRARIES}
+    ${LIBCORO_LIBRARIES}
+)
+
+set (server_sources
      util.cc
      find_path.c
      sio.cc
@@ -54,15 +70,9 @@ set (common_sources
      iobuf.cc
      coio_buf.cc
      pickle.cc
-     coro.cc
      stat.cc
-     object.cc
-     exception.cc
      ipc.cc
      errinj.cc
-     errcode.c
-     assoc.c
-     say.cc
      fio.c
      crc32.c
      random.c
@@ -90,19 +100,16 @@ set (common_sources
 )
 
 if (ENABLE_TRACE)
-    set (common_sources ${common_sources} trace.c)
+    set (server_sources ${server_sources} trace.c)
 endif()
 
-set_source_files_compile_flags(${common_sources})
-add_library(core STATIC ${common_sources})
-target_link_libraries(core pthread)
+set_source_files_compile_flags(${server_sources})
+add_library(server STATIC ${server_sources})
+target_link_libraries(server core pthread)
 
-set (common_libraries core small salad misc bitset msgpuck)
+set (common_libraries server core misc bitset msgpuck)
 
 list(APPEND common_libraries
-    ${LIBEV_LIBRARIES}
-    ${LIBEIO_LIBRARIES}
-    ${LIBCORO_LIBRARIES}
     ${LIBGOPT_LIBRARIES}
     ${LIBCJSON_LIBRARIES}
     ${LIBYAML_LIBRARIES}
@@ -110,10 +117,6 @@ list(APPEND common_libraries
     ${LUAJIT_LIB}
 )
 
-set (THREAD_LIB pthread)
-
-set (common_libraries ${common_libraries} ${THREAD_LIB})
-
 if (TARGET_OS_LINUX OR TARGET_OS_DEBIAN_FREEBSD)
     set (common_libraries ${common_libraries} dl)
 endif()
diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt
index 764d85c154a1099d74d74ddd10116b891b206649..7ec1dcf7080dbf24a559f48565eacdcf3a02286f 100644
--- a/src/box/CMakeLists.txt
+++ b/src/box/CMakeLists.txt
@@ -20,6 +20,8 @@ add_library(box
     iproto.cc
     iproto_constants.c
     iproto_port.cc
+    errcode.c
+    error.cc
     xrow.cc
     xlog.cc
     tuple.cc
diff --git a/src/box/bitset_index.cc b/src/box/bitset_index.cc
index 992af64cde06bac8a16f3311293bf7532f7e40a8..4b04adb8d550eddf4947343f128ff5180742c868 100644
--- a/src/box/bitset_index.cc
+++ b/src/box/bitset_index.cc
@@ -32,7 +32,6 @@
 #include <string.h>
 
 #include "tuple.h"
-#include "exception.h"
 #include "bitset/index.h"
 
 static inline struct tuple *
diff --git a/src/box/cluster.cc b/src/box/cluster.cc
index 031ecff6a681226a6b34d9a7a5087fd710f22cd2..56490b4ce8f485683c1ed9c92bef38e746345f1d 100644
--- a/src/box/cluster.cc
+++ b/src/box/cluster.cc
@@ -29,7 +29,6 @@
 #include "box.h"
 #include "cluster.h"
 #include "recovery.h"
-#include "exception.h"
 
 /**
  * Globally unique identifier of this cluster.
diff --git a/src/box/engine.cc b/src/box/engine.cc
index ffa5283039967573ee6cf4774f36f7d7c7a2d9a9..13cb1492246f00d8567cd085e034cd6e066edaa2 100644
--- a/src/box/engine.cc
+++ b/src/box/engine.cc
@@ -28,7 +28,6 @@
  */
 #include "engine.h"
 #include "space.h"
-#include "exception.h"
 #include "salad/rlist.h"
 #include <stdlib.h>
 #include <string.h>
diff --git a/src/box/engine.h b/src/box/engine.h
index 478ea0e0438a34c4426d98d047955c985276f26d..c811cef6d5074f6e8c461464b11e1ddaa0ca440b 100644
--- a/src/box/engine.h
+++ b/src/box/engine.h
@@ -28,7 +28,6 @@
  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#include <exception.h>
 #include "index.h"
 
 struct space;
diff --git a/src/box/engine_memtx.cc b/src/box/engine_memtx.cc
index 2118b15d141175a8d3d131c994cc8a89290777b8..2011f03742b94176b6912aba562f878bde5b2452 100644
--- a/src/box/engine_memtx.cc
+++ b/src/box/engine_memtx.cc
@@ -36,7 +36,6 @@
 #include "rtree_index.h"
 #include "bitset_index.h"
 #include "space.h"
-#include "exception.h"
 #include "salad/rlist.h"
 #include <stdlib.h>
 #include <string.h>
diff --git a/src/box/engine_sophia.cc b/src/box/engine_sophia.cc
index efccbb2a58afd3a6ff94e771829f67def33c4c5b..a8c158dfbca82810f2bcf8bb7aafead9bc898f06 100644
--- a/src/box/engine_sophia.cc
+++ b/src/box/engine_sophia.cc
@@ -36,7 +36,6 @@
 #include "index.h"
 #include "sophia_index.h"
 #include "space.h"
-#include "exception.h"
 #include "salad/rlist.h"
 #include <sophia.h>
 #include <stdlib.h>
diff --git a/src/errcode.c b/src/box/errcode.c
similarity index 98%
rename from src/errcode.c
rename to src/box/errcode.c
index 9cc3615e73f1922f02b5001eecc4e24bdd0d496a..e90747e43963eaeedb07ebc8adbb0a292a7e9696 100644
--- a/src/errcode.c
+++ b/src/box/errcode.c
@@ -27,6 +27,7 @@
  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+#include "errcode.h"
 
 #define ERRCODE_RECORD_MEMBER(s, f, d) {	\
 	.errstr = #s,				\
diff --git a/src/errcode.h b/src/box/errcode.h
similarity index 97%
rename from src/errcode.h
rename to src/box/errcode.h
index a128fe3319cd0c905a34418de487a224cfc63ae1..7d0f973c1a280d46e0aa7be23013e69cffa1ba7c 100644
--- a/src/errcode.h
+++ b/src/box/errcode.h
@@ -1,5 +1,5 @@
-#ifndef TARANTOOL_ERRCODE_H_INCLUDED
-#define TARANTOOL_ERRCODE_H_INCLUDED
+#ifndef TARANTOOL_BOX_ERRCODE_H_INCLUDED
+#define TARANTOOL_BOX_ERRCODE_H_INCLUDED
 /*
  * Redistribution and use in source and binary forms, with or
  * without modification, are permitted provided that the following
@@ -32,14 +32,16 @@
 
 #include "trivia/util.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 struct errcode_record {
 	const char *errstr;
 	const char *errdesc;
 	uint8_t errflags;
 };
 
-enum { TNT_ERRMSG_MAX = 512 };
-
 /*
  * To add a new error code to Tarantool, extend this array.
  *
@@ -172,4 +174,8 @@ static inline const char *tnt_errcode_desc(uint32_t errcode)
 	return tnt_error_codes[errcode].errdesc;
 }
 
-#endif /* TARANTOOL_ERRCODE_H_INCLUDED */
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* TARANTOOL_BOX_ERRCODE_H_INCLUDED */
diff --git a/src/box/error.cc b/src/box/error.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f3fc39e74e8005bdf4fc0ff8f2fb7c1324a2bba8
--- /dev/null
+++ b/src/box/error.cc
@@ -0,0 +1,75 @@
+/*
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the
+ *    following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "error.h"
+#include <stdio.h>
+#include <typeinfo>
+
+ClientError::ClientError(const char *file, unsigned line, uint32_t errcode, ...)
+	: Exception(file, line)
+{
+	m_errcode = errcode;
+	va_list ap;
+	va_start(ap, errcode);
+	vsnprintf(m_errmsg, sizeof(m_errmsg) - 1,
+		  tnt_errcode_desc(m_errcode), ap);
+	m_errmsg[sizeof(m_errmsg) - 1] = 0;
+	va_end(ap);
+}
+
+ClientError::ClientError(const char *file, unsigned line, const char *msg,
+			 uint32_t errcode)
+	: Exception(file, line)
+{
+	m_errcode = errcode;
+	strncpy(m_errmsg, msg, sizeof(m_errmsg) - 1);
+	m_errmsg[sizeof(m_errmsg) - 1] = 0;
+}
+
+void
+ClientError::log() const
+{
+	_say(S_ERROR, m_file, m_line, NULL, "%s: %s", tnt_errcode_str(m_errcode),
+	     m_errmsg);
+}
+
+
+uint32_t
+ClientError::get_code_for_foreign_exception(const Exception *e)
+{
+	if (typeid(*e) == typeid(OutOfMemory))
+		return ER_MEMORY_ISSUE;
+	return ER_PROC_LUA;
+}
+
+ErrorInjection::ErrorInjection(const char *file, unsigned line, const char *msg)
+	: LoggedError(file, line, ER_INJECTION, msg)
+{
+	/* nothing */
+}
+
diff --git a/src/box/error.h b/src/box/error.h
new file mode 100644
index 0000000000000000000000000000000000000000..908e46c320fa842a02cbb020b74662cfd631943a
--- /dev/null
+++ b/src/box/error.h
@@ -0,0 +1,85 @@
+#ifndef TARANTOOL_BOX_ERROR_H_INCLUDED
+#define TARANTOOL_BOX_ERROR_H_INCLUDED
+/*
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the
+ *    following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "errcode.h"
+#include "exception.h"
+
+class ClientError: public Exception {
+public:
+	virtual void raise()
+	{
+		throw this;
+	}
+
+	virtual void log() const;
+
+	int
+	errcode() const
+	{
+		return m_errcode;
+	}
+
+	ClientError(const char *file, unsigned line, uint32_t errcode, ...);
+	/* A special constructor for lbox_raise */
+	ClientError(const char *file, unsigned line, const char *msg,
+		    uint32_t errcode);
+
+	static uint32_t get_code_for_foreign_exception(const Exception *e);
+private:
+	/* client errno code */
+	int m_errcode;
+};
+
+class LoggedError: public ClientError {
+public:
+	template <typename ... Args>
+	LoggedError(const char *file, unsigned line, uint32_t errcode, Args ... args)
+		: ClientError(file, line, errcode, args...)
+	{
+		/* TODO: actually calls ClientError::log */
+		log();
+	}
+};
+
+class IllegalParams: public LoggedError {
+public:
+	template <typename ... Args>
+	IllegalParams(const char *file, unsigned line, const char *format,
+		      Args ... args)
+		:LoggedError(file, line, ER_ILLEGAL_PARAMS,
+			     format, args...) {}
+};
+
+class ErrorInjection: public LoggedError {
+public:
+	ErrorInjection(const char *file, unsigned line, const char *msg);
+};
+
+#endif /* TARANTOOL_BOX_ERROR_H_INCLUDED */
diff --git a/src/box/hash_index.cc b/src/box/hash_index.cc
index 75b60d2bc47cfa69a6046180344a6d1d9d8b81ac..3591a3ff4318abc3d6278c9eb01019e4d2e5d87a 100644
--- a/src/box/hash_index.cc
+++ b/src/box/hash_index.cc
@@ -29,7 +29,6 @@
 #include "hash_index.h"
 #include "say.h"
 #include "tuple.h"
-#include "exception.h"
 #include "errinj.h"
 
 #include "third_party/PMurHash.h"
diff --git a/src/box/index.cc b/src/box/index.cc
index 209d92aa73d62bd90b2765a0cc983677231b36f4..c577549b8e72ed581b561171ca4503ff27d6a5af 100644
--- a/src/box/index.cc
+++ b/src/box/index.cc
@@ -33,7 +33,6 @@
 #include "sophia_index.h"
 #include "tuple.h"
 #include "say.h"
-#include "exception.h"
 #include "schema.h"
 
 STRS(iterator_type, ITERATOR_TYPE);
diff --git a/src/box/index.h b/src/box/index.h
index a86fd2f1c7f5e6110dc620671d396727921467a4..7b609c3a055826ec31af032e3bc974a9e44b9640 100644
--- a/src/box/index.h
+++ b/src/box/index.h
@@ -33,7 +33,6 @@
 
 #include "object.h"
 #include "key_def.h"
-#include "exception.h"
 
 struct tuple;
 
diff --git a/src/box/iproto.cc b/src/box/iproto.cc
index b7a371d67ca258b902d6d417399599b54ffb9b8c..c2b04236d9dff9a8d9d47821b2209efa34dffed9 100644
--- a/src/box/iproto.cc
+++ b/src/box/iproto.cc
@@ -34,8 +34,6 @@
 
 #include "iproto_port.h"
 #include "tarantool.h"
-#include "exception.h"
-#include "errcode.h"
 #include "fiber.h"
 #include "say.h"
 #include "evio.h"
@@ -584,7 +582,7 @@ iproto_flush(struct iobuf *iobuf, int fd, struct obuf_svp *svp)
 		nwr = sio_writev(fd, iov, iovcnt);
 
 		sio_add_to_iov(iov, svp->iov_len);
-	} catch (Exception *) {
+	} catch (SocketError *) {
 		sio_add_to_iov(iov, svp->iov_len);
 		throw;
 	}
@@ -660,7 +658,7 @@ iproto_process_dml(struct iproto_request *ireq)
 	iproto_port_init(&port, out, ireq->header.sync);
 	try {
 		box_process((struct port *) &port, &ireq->request);
-	} catch (ClientError *e) {
+	} catch (Exception *e) {
 		if (port.found)
 			obuf_rollback_to_svp(out, &port.svp);
 		iproto_reply_error(out, e, ireq->header.sync);
@@ -714,7 +712,7 @@ iproto_process_admin(struct iproto_request *ireq)
 			tnt_raise(ClientError, ER_UNKNOWN_REQUEST_TYPE,
 				   (uint32_t) ireq->header.type);
 		}
-	} catch (ClientError *e) {
+	} catch (Exception *e) {
 		say_error("admin command error: %s", e->errmsg());
 		iproto_reply_error(&iobuf->out, e, ireq->header.sync);
 	}
@@ -763,7 +761,11 @@ iproto_process_connect(struct iproto_request *request)
 			   IPROTO_GREETING_SIZE);
 		if (! rlist_empty(&session_on_connect))
 			session_run_on_connect_triggers(con->session);
-	} catch (ClientError *e) {
+	} catch (SocketError *e) {
+		e->log();
+		iproto_connection_close(con);
+		return;
+	} catch (Exception *e) {
 		iproto_reply_error(&iobuf->out, e, request->header.type);
 		try {
 			iproto_flush(iobuf, fd, &con->write_pos);
@@ -772,10 +774,6 @@ iproto_process_connect(struct iproto_request *request)
 		}
 		iproto_connection_close(con);
 		return;
-	} catch (Exception *e) {
-		e->log();
-		iproto_connection_close(con);
-		return;
 	}
 	/*
 	 * Connect is synchronous, so no one could have been
diff --git a/src/box/iproto_port.cc b/src/box/iproto_port.cc
index b1f227dd1d36d1f2ce459f9ca582ee2f4a6c3174..d2810a08b550f478bdda7ab3b0dcfa7cf2f12858 100644
--- a/src/box/iproto_port.cc
+++ b/src/box/iproto_port.cc
@@ -77,17 +77,27 @@ iproto_reply_ping(struct obuf *out, uint64_t sync)
 	obuf_dup(out, &reply, sizeof(reply));
 }
 
+static inline uint32_t
+get_errcode(const Exception *e)
+{
+	const ClientError *error = dynamic_cast<const ClientError *>(e);
+	if (error)
+		return error->errcode();
+	return ClientError::get_code_for_foreign_exception(e);
+}
+
 void
-iproto_reply_error(struct obuf *out, const ClientError *e, uint64_t sync)
+iproto_reply_error(struct obuf *out, const Exception *e, uint64_t sync)
 {
 	uint32_t msg_len = strlen(e->errmsg());
+	uint32_t errcode = get_errcode(e);
 
 	struct iproto_header_bin header = iproto_header_bin;
 	struct iproto_body_bin body = iproto_error_bin;
 
 	uint32_t len = sizeof(header) - 5 + sizeof(body) + msg_len;
 	header.v_len = mp_bswap_u32(len);
-	header.v_code = mp_bswap_u32(iproto_encode_error(e->errcode()));
+	header.v_code = mp_bswap_u32(iproto_encode_error(errcode));
 	header.v_sync = mp_bswap_u64(sync);
 
 	body.v_data_len = mp_bswap_u32(msg_len);
diff --git a/src/box/iproto_port.h b/src/box/iproto_port.h
index 0613854abf911c67eb00b04c6ccb513f3aaad344..9349f71c60c568605bc84ae191188d23ed0d8015 100644
--- a/src/box/iproto_port.h
+++ b/src/box/iproto_port.h
@@ -86,6 +86,6 @@ iproto_reply_ping(struct obuf *out, uint64_t sync);
 
 /** Send an error packet back. */
 void
-iproto_reply_error(struct obuf *out, const ClientError *e, uint64_t sync);
+iproto_reply_error(struct obuf *out, const Exception *e, uint64_t sync);
 
 #endif /* TARANTOOL_IPROTO_PORT_H_INCLUDED */
diff --git a/src/box/key_def.cc b/src/box/key_def.cc
index 7a071d490e7d15a0cbfc22193b8cf4883d56fba2..54b655dccb2fd5750be9adc3c4d38e450845732f 100644
--- a/src/box/key_def.cc
+++ b/src/box/key_def.cc
@@ -31,7 +31,6 @@
 #include "schema.h"
 #include <stdlib.h>
 #include <stdio.h>
-#include "exception.h"
 
 const char *field_type_strs[] = {"UNKNOWN", "NUM", "STR", "ARRAY", "NUMBER", ""};
 STRS(index_type, ENUM_INDEX_TYPE);
diff --git a/src/box/key_def.h b/src/box/key_def.h
index b347740c5415829e443838c2b18da7e258c74412..574b2651c000ae5c131cc2d83535a60a9b01c0f2 100644
--- a/src/box/key_def.h
+++ b/src/box/key_def.h
@@ -30,7 +30,7 @@
  */
 #include "trivia/util.h"
 #include "salad/rlist.h"
-#include <exception.h>
+#include "error.h"
 #include "msgpuck/msgpuck.h"
 #define RB_COMPACT 1
 #include "third_party/rb.h"
diff --git a/src/box/lua/error.cc b/src/box/lua/error.cc
index 00d3baabef31e9ec42db683a600fc6b1e81eb643..6c817a6f385e8d1171590fd3d0e9938f69c74b97 100644
--- a/src/box/lua/error.cc
+++ b/src/box/lua/error.cc
@@ -35,10 +35,10 @@ extern "C" {
 } /* extern "C" */
 
 #include <fiber.h>
-#include <errcode.h>
 #include <errinj.h>
 
 #include "lua/utils.h"
+#include "box/error.h"
 
 static int
 lbox_raise(lua_State *L)
diff --git a/src/box/replication.cc b/src/box/replication.cc
index ab7bbaa2999ae392e27b04795af03625cec886ca..dd54ab01679a3591866fa042923d7a9419c41686 100644
--- a/src/box/replication.cc
+++ b/src/box/replication.cc
@@ -51,6 +51,7 @@
 #include "box/vclock.h"
 #include "scoped_guard.h"
 #include "xrow.h"
+#include "coeio.h"
 
 /** Replication topology
  * ----------------------
diff --git a/src/box/rtree_index.cc b/src/box/rtree_index.cc
index 5869d24d00d239786f7a8d62aa21b84577452a4d..a54ec9ffc2a9c2aabcdaa36d424dd6f8ca280c36 100644
--- a/src/box/rtree_index.cc
+++ b/src/box/rtree_index.cc
@@ -29,7 +29,6 @@
 #include "rtree_index.h"
 #include "tuple.h"
 #include "space.h"
-#include "exception.h"
 #include "errinj.h"
 #include "fiber.h"
 #include "small/small.h"
diff --git a/src/box/schema.h b/src/box/schema.h
index cbd77926c2fe8d50f7602a04b1cc873b2d48c94d..201293ec78339c88905a0d220ec32e37669d31b3 100644
--- a/src/box/schema.h
+++ b/src/box/schema.h
@@ -28,7 +28,7 @@
  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#include "exception.h"
+#include "error.h"
 #include <stdio.h> /* snprintf */
 
 enum schema_id {
@@ -163,5 +163,4 @@ func_by_name(const char *name, uint32_t name_len)
 bool
 schema_find_grants(const char *type, uint32_t id);
 
-
 #endif /* INCLUDES_TARANTOOL_BOX_SCHEMA_H */
diff --git a/src/box/session.cc b/src/box/session.cc
index 28df06060235b74e70302c242b68df984aa32f7c..b0f95197607349dc44eb78119460f5675be0c67e 100644
--- a/src/box/session.cc
+++ b/src/box/session.cc
@@ -32,7 +32,6 @@
 
 #include "assoc.h"
 #include "trigger.h"
-#include "exception.h"
 #include "random.h"
 #include <sys/socket.h>
 #include "user.h"
diff --git a/src/box/sophia_index.cc b/src/box/sophia_index.cc
index ebe9abb726ad8edc701406447e61c6d3c1d0fe0c..8191090c1fac3af21a31a502fb5ac1c2747d5903 100644
--- a/src/box/sophia_index.cc
+++ b/src/box/sophia_index.cc
@@ -30,7 +30,6 @@
 #include "say.h"
 #include "tuple.h"
 #include "scoped_guard.h"
-#include "exception.h"
 #include "errinj.h"
 #include "schema.h"
 #include "space.h"
diff --git a/src/box/space.cc b/src/box/space.cc
index 8350b8cdd4bfb1fb9ff86abb26a7bf18c7e89542..413bfc03c4f51e0e887dea95f1d638770ff2d5f1 100644
--- a/src/box/space.cc
+++ b/src/box/space.cc
@@ -29,7 +29,6 @@
 #include "space.h"
 #include <stdlib.h>
 #include <string.h>
-#include <exception.h>
 #include "tuple.h"
 #include "scoped_guard.h"
 #include "trigger.h"
diff --git a/src/box/space.h b/src/box/space.h
index f171e68ca8d49f6920ebf41be45bac91036b0875..d6168e611d5674d15145fe2312e68e67ab40f082 100644
--- a/src/box/space.h
+++ b/src/box/space.h
@@ -32,7 +32,6 @@
 #include "key_def.h"
 #include "engine.h"
 #include "salad/rlist.h"
-#include <exception.h>
 
 struct space {
 	struct access access[BOX_USER_MAX];
diff --git a/src/box/tree_index.cc b/src/box/tree_index.cc
index d877a09e4611e869852e024340f119cec95808f2..122e068bba26dd07b87cb44ce2acee4ca1f0279c 100644
--- a/src/box/tree_index.cc
+++ b/src/box/tree_index.cc
@@ -29,7 +29,6 @@
 #include "tree_index.h"
 #include "tuple.h"
 #include "space.h"
-#include "exception.h"
 #include "errinj.h"
 #include "memory.h"
 #include "fiber.h"
diff --git a/src/box/tuple.cc b/src/box/tuple.cc
index d00728e2c8134a197c5242071fbcf628b359545c..0791038dbcfdb5790a0f7f76cbe9900d13070978 100644
--- a/src/box/tuple.cc
+++ b/src/box/tuple.cc
@@ -33,7 +33,6 @@
 
 #include "key_def.h"
 #include "tuple_update.h"
-#include <exception.h>
 #include <stdio.h>
 
 /** Global table of tuple formats */
diff --git a/src/box/tuple_update.cc b/src/box/tuple_update.cc
index 6026259d2f61eb851787e335158be0e8c83e2f1f..df68bb3bbd196d484b1311f99f58ef0305bf4672 100644
--- a/src/box/tuple_update.cc
+++ b/src/box/tuple_update.cc
@@ -33,7 +33,7 @@
 #include "third_party/queue.h"
 
 #include "salad/rope.h"
-#include <exception.h>
+#include "error.h"
 #include "msgpuck/msgpuck.h"
 
 /** UPDATE request implementation.
diff --git a/src/box/vclock.h b/src/box/vclock.h
index 4318b54bad9fe89bdc2fe05cd34bb9b8653b2646..d438a7bdfd138ab69fb4abb09cf21b394d66301f 100644
--- a/src/box/vclock.h
+++ b/src/box/vclock.h
@@ -192,7 +192,7 @@ vclockset_isearch(vclockset_t *set, struct vclock *key)
 #if defined(__cplusplus)
 } /* extern "C" */
 
-#include "exception.h"
+#include "error.h"
 
 /**
  * Allocate a new vclock object and initialize it
diff --git a/src/box/xrow.cc b/src/box/xrow.cc
index 1f5761d313d46ec91a71d6c5cb674026ba28bdda..aedc8d19d3d9e91799703beb3041ec0753c4819e 100644
--- a/src/box/xrow.cc
+++ b/src/box/xrow.cc
@@ -28,7 +28,6 @@
  */
 #include "xrow.h"
 #include "msgpuck/msgpuck.h"
-#include "exception.h"
 #include "fiber.h"
 #include "tt_uuid.h"
 #include "vclock.h"
diff --git a/src/coeio.cc b/src/coeio.cc
index 9ff129322647ac4d9b8d0e5a80b623a1b056a4aa..6ea828224425f53194e41b4c76aca5f351fb75e8 100644
--- a/src/coeio.cc
+++ b/src/coeio.cc
@@ -283,3 +283,27 @@ coeio_resolve(int socktype, const char *host, const char *port,
 		return NULL;
 	return result;
 }
+
+ssize_t
+cord_cojoin_cb(va_list ap)
+{
+	struct cord *cord = va_arg(ap, struct cord *);
+	void *retval = NULL;
+	int res = tt_pthread_join(cord->id, &retval);
+	return res;
+}
+
+int
+cord_cojoin(struct cord *cord)
+{
+	assert(cord() != cord); /* Can't join self. */
+	int rc = coeio_custom(cord_cojoin_cb, TIMEOUT_INFINITY, cord);
+	if (rc == 0 && cord->exception) {
+		Exception::move(cord, cord());
+		cord_destroy(cord);
+		cord()->exception->raise(); /* re-throw exception from cord */
+	}
+	cord_destroy(cord);
+	return rc;
+}
+
diff --git a/src/coeio.h b/src/coeio.h
index 6536063c5560f2201600f96576b025de69ed76bd..da7d18ce0d6c65274eee9de91ef8961b2b1776a8 100644
--- a/src/coeio.h
+++ b/src/coeio.h
@@ -67,4 +67,17 @@ coeio_resolve(int socktype, const char *host, const char *port,
 #if defined(__cplusplus)
 }
 #endif
+
+struct cord;
+/**
+ * \brief Yield until \a cord has terminated.
+ * If \a cord has terminated with an uncaught exception
+ * **re-throws** this exception in the calling cord/fiber.
+ * \param cord cord
+ * \sa pthread_join()
+ * \return 0 on success
+ */
+int
+cord_cojoin(struct cord *cord);
+
 #endif /* TARANTOOL_COEIO_H_INCLUDED */
diff --git a/src/coio.cc b/src/coio.cc
index b8b5e5edd2f9e6d68109efc266e372eca31a02b7..e2903365f1f0cb0c18aa77eda240d63fdf902002 100644
--- a/src/coio.cc
+++ b/src/coio.cc
@@ -410,7 +410,7 @@ coio_flush(int fd, struct iovec *iov, ssize_t offset, int iovcnt)
 		sio_add_to_iov(iov, -offset);
 		nwr = sio_writev(fd, iov, iovcnt);
 		sio_add_to_iov(iov, offset);
-	} catch (Exception *e) {
+	} catch (SocketError *e) {
 		sio_add_to_iov(iov, offset);
 		throw;
 	}
@@ -578,6 +578,7 @@ coio_service_on_accept(struct evio_service *evio_service,
 		iobuf = iobuf_new(iobuf_name);
 		f = fiber_new(fiber_name, service->handler);
 	} catch (Exception *e) {
+		e->log();
 		say_error("can't create a handler fiber, dropping client connection");
 		evio_close(loop(), &coio);
 		if (iobuf)
diff --git a/src/coro.cc b/src/coro.cc
index 74bdb283c9e7c931aeb72e9b92c4c0c47a1944b7..eb3aebaafc27111563bdfd9616daf5c836737e9d 100644
--- a/src/coro.cc
+++ b/src/coro.cc
@@ -51,8 +51,7 @@ tarantool_coro_create(struct tarantool_coro *coro,
 					+ slab_sizeof();
 
 	if (coro->stack == NULL) {
-		tnt_raise(LoggedError, ER_MEMORY_ISSUE,
-			  sizeof(coro->stack_size),
+		tnt_raise(OutOfMemory, sizeof(coro->stack_size),
 			  "mmap", "coro stack");
 	}
 
diff --git a/src/evio.cc b/src/evio.cc
index 7ce4e681b19e447824aa7d212c62f9910b8f3e69..1d3cbead4a9809642e2d4b7255687c67215ab44d 100644
--- a/src/evio.cc
+++ b/src/evio.cc
@@ -297,7 +297,7 @@ evio_service_init(ev_loop *loop,
 
 	struct uri u;
 	if (uri_parse(&u, uri) || u.service == NULL)
-		tnt_raise(IllegalParams, "invalid uri for bind: %s", uri);
+		tnt_raise(SocketError, -1, "invalid uri for bind: %s", uri);
 
 	snprintf(service->serv, sizeof(service->serv), "%.*s",
 		 (int) u.service_len, u.service);
diff --git a/src/exception.cc b/src/exception.cc
index aefc9f26e53c02cdd8f4d13f5c48b3543e781e3f..a9e45e42c6163fc60f6093cdf08051bf5e9d971a 100644
--- a/src/exception.cc
+++ b/src/exception.cc
@@ -33,10 +33,10 @@
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
+#include <typeinfo>
 
-/* Statically allocate out-of-memory exception */
-ClientError out_of_memory(__FILE__, __LINE__, ER_MEMORY_ISSUE, 0,
-			  "exception", "new");
+static OutOfMemory out_of_memory(__FILE__, __LINE__,
+				 sizeof(OutOfMemory), "malloc", "exception");
 
 void *
 Exception::operator new(size_t size)
@@ -56,7 +56,7 @@ Exception::operator new(size_t size)
 		}
 		free(cord->exception);
 	}
-	cord->exception = (ClientError *) malloc(size);
+	cord->exception = (Exception *) malloc(size);
 	if (cord->exception) {
 		cord->exception_size = size;
 		return cord->exception;
@@ -112,9 +112,17 @@ Exception::Exception(const Exception& e)
 	memcpy(m_errmsg, e.m_errmsg, sizeof(m_errmsg));
 }
 
+void
+Exception::log() const
+{
+	_say(S_ERROR, m_file, m_line, "%s %s",
+	     typeid(*this).name(), m_errmsg);
+}
+
+
 SystemError::SystemError(const char *file, unsigned line)
 	: Exception(file, line),
-	  m_errnum(errno)
+	  m_errno(errno)
 {
 	/* nothing */
 }
@@ -137,42 +145,17 @@ SystemError::init(const char *format, va_list ap)
 void
 SystemError::log() const
 {
-	_say(S_SYSERROR, m_file, m_line, strerror(m_errnum), "SystemError %s",
+	_say(S_SYSERROR, m_file, m_line, strerror(m_errno), "SystemError %s",
 	     m_errmsg);
 }
 
-
-ClientError::ClientError(const char *file, unsigned line, uint32_t errcode, ...)
-	: Exception(file, line)
-{
-	m_errcode = errcode;
-	va_list ap;
-	va_start(ap, errcode);
-	vsnprintf(m_errmsg, sizeof(m_errmsg) - 1,
-		  tnt_errcode_desc(m_errcode), ap);
-	m_errmsg[sizeof(m_errmsg) - 1] = 0;
-	va_end(ap);
-}
-
-ClientError::ClientError(const char *file, unsigned line, const char *msg,
-			 uint32_t errcode)
-	: Exception(file, line)
+OutOfMemory::OutOfMemory(const char *file, unsigned line,
+			 size_t amount, const char *allocator,
+			 const char *object)
+	:SystemError(file, line)
 {
-	m_errcode = errcode;
-	strncpy(m_errmsg, msg, sizeof(m_errmsg) - 1);
-	m_errmsg[sizeof(m_errmsg) - 1] = 0;
+	m_errno = ENOMEM;
+	snprintf(m_errmsg, sizeof(m_errmsg),
+		 "Failed to allocate %u bytes in %s for %s",
+		 (unsigned) amount, allocator, object);
 }
-
-void
-ClientError::log() const
-{
-	_say(S_ERROR, m_file, m_line, NULL, "%s: %s", tnt_errcode_str(m_errcode),
-	     m_errmsg);
-}
-
-ErrorInjection::ErrorInjection(const char *file, unsigned line, const char *msg)
-	: LoggedError(file, line, ER_INJECTION, msg)
-{
-	/* nothing */
-}
-
diff --git a/src/exception.h b/src/exception.h
index d9afb096db2bb0d1903cb40884c2b996beba49c6..c241523a2abd770491c3894643ce64160e72a9a6 100644
--- a/src/exception.h
+++ b/src/exception.h
@@ -30,11 +30,12 @@
  */
 #include "object.h"
 #include <stdarg.h>
-#include "errcode.h"
 #include "say.h"
 
 struct cord;
 
+enum { TNT_ERRMSG_MAX = 512 };
+
 class Exception: public Object {
 public:
 	void *operator new(size_t size);
@@ -51,7 +52,7 @@ class Exception: public Object {
 		return m_errmsg;
 	}
 
-	virtual void log() const = 0;
+	virtual void log() const;
 	virtual ~Exception() {}
 
 	static void init(struct cord *cord);
@@ -84,7 +85,7 @@ class SystemError: public Exception {
 	int
 	errnum() const
 	{
-		return m_errnum;
+		return m_errno;
 	}
 
 	virtual void log() const;
@@ -98,60 +99,16 @@ class SystemError: public Exception {
 	void
 	init(const char *format, va_list ap);
 
-private:
+protected:
 	/* system errno */
-	int m_errnum;
-};
-
-class ClientError: public Exception {
-public:
-	virtual void raise()
-	{
-		throw this;
-	}
-
-	virtual void log() const;
-
-	int
-	errcode() const
-	{
-		return m_errcode;
-	}
-
-	ClientError(const char *file, unsigned line, uint32_t errcode, ...);
-	/* A special constructor for lbox_raise */
-	ClientError(const char *file, unsigned line, const char *msg,
-		    uint32_t errcode);
-private:
-	/* client errno code */
-	int m_errcode;
-};
-
-extern ClientError out_of_memory;
-
-class LoggedError: public ClientError {
-public:
-	template <typename ... Args>
-	LoggedError(const char *file, unsigned line, uint32_t errcode, Args ... args)
-		: ClientError(file, line, errcode, args...)
-	{
-		/* TODO: actually calls ClientError::log */
-		log();
-	}
-};
-
-class IllegalParams: public LoggedError {
-public:
-	template <typename ... Args>
-	IllegalParams(const char *file, unsigned line, const char *format,
-		      Args ... args)
-		:LoggedError(file, line, ER_ILLEGAL_PARAMS,
-			     format, args...) {}
+	int m_errno;
 };
 
-class ErrorInjection: public LoggedError {
+class OutOfMemory: public SystemError {
 public:
-	ErrorInjection(const char *file, unsigned line, const char *msg);
+	OutOfMemory(const char *file, unsigned line,
+		    size_t amount, const char *allocator,
+		    const char *object);
 };
 
 #define tnt_raise(...) tnt_raise0(__VA_ARGS__)
diff --git a/src/fiber.cc b/src/fiber.cc
index b8b2dd07d87bf27b52501ef3793add9d7875e41f..b6f7109b531cd75253ea50c260e876019934b3f2 100644
--- a/src/fiber.cc
+++ b/src/fiber.cc
@@ -33,11 +33,9 @@
 #include <string.h>
 
 #include "say.h"
-#include "stat.h"
 #include "assoc.h"
 #include "memory.h"
 #include "trigger.h"
-#include "coeio.h"
 
 static struct cord main_cord;
 __thread struct cord *cord_ptr = NULL;
@@ -76,12 +74,13 @@ fiber_call(struct fiber *callee, ...)
 	va_end(callee->f_data);
 }
 
-void
+bool
 fiber_checkstack()
 {
 	struct cord *cord = cord();
 	if (cord->sp + 1 - cord->stack >= FIBER_CALL_STACK)
-		tnt_raise(ClientError, ER_FIBER_STACK);
+		return true;
+	return false;
 }
 
 /** Interrupt a synchronous wait of a fiber inside the event loop.
@@ -397,10 +396,7 @@ fiber_loop(void *data __attribute__((unused)))
 		} catch (Exception *e) {
 			e->log();
 		} catch (...) {
-			/*
-			 * This can only happen in case of a bug
-			 * server bug.
-			 */
+			/* This can only happen in case of a server bug. */
 			say_error("fiber `%s': unknown exception",
 				fiber_name(fiber()));
 			panic("fiber `%s': exiting", fiber_name(fiber()));
@@ -638,29 +634,6 @@ cord_join(struct cord *cord)
 	return res;
 }
 
-ssize_t
-cord_cojoin_cb(va_list ap)
-{
-	struct cord *cord = va_arg(ap, struct cord *);
-	void *retval = NULL;
-	int res = tt_pthread_join(cord->id, &retval);
-	return res;
-}
-
-int
-cord_cojoin(struct cord *cord)
-{
-	assert(cord() != cord); /* Can't join self. */
-	int rc = coeio_custom(cord_cojoin_cb, TIMEOUT_INFINITY, cord);
-	if (rc == 0 && cord->exception) {
-		Exception::move(cord, cord());
-		cord_destroy(cord);
-		cord()->exception->raise(); /* re-throw exception from cord */
-	}
-	cord_destroy(cord);
-	return rc;
-}
-
 void
 fiber_init(void)
 {
diff --git a/src/fiber.h b/src/fiber.h
index c6433d0b902a63794f6f68f7f0ad72768fb2aa06..3f72521aef10fafcc2ffb71c61301faed0bf69c5 100644
--- a/src/fiber.h
+++ b/src/fiber.h
@@ -202,23 +202,14 @@ cord_start(struct cord *cord, const char *name,
 int
 cord_join(struct cord *cord);
 
-/**
- * \brief Yield until \a cord has terminated.
- * If \a cord has terminated with an uncaught exception
- * **re-throws** this exception in the calling cord/fiber.
- * \param cord cord
- * \sa pthread_join()
- * \return 0 on success
- */
-int
-cord_cojoin(struct cord *cord);
-
 static inline void
 cord_set_name(const char *name)
 {
 	snprintf(cord()->name, FIBER_NAME_MAX, "%s", name);
 }
 
+void
+cord_destroy(struct cord *cord);
 
 void fiber_init(void);
 void fiber_free(void);
@@ -233,7 +224,7 @@ fiber_name(struct fiber *f)
 	return region_name(&f->gc);
 }
 
-void
+bool
 fiber_checkstack();
 
 void fiber_yield(void);
diff --git a/src/iobuf.cc b/src/iobuf.cc
index 4f565693b4b43f19dd80a4d35e54c55bcc19aa4f..07027ffffd0012f37ba2eedbefe94ffa32191023 100644
--- a/src/iobuf.cc
+++ b/src/iobuf.cc
@@ -100,8 +100,7 @@ static inline void
 obuf_init_pos(struct obuf *buf, size_t pos)
 {
 	if (pos >= IOBUF_IOV_MAX) {
-		tnt_raise(LoggedError, ER_MEMORY_ISSUE, buf->pos,
-			  "obuf_init_pos", "iovec");
+		tnt_raise(OutOfMemory, buf->pos, "obuf_init_pos", "iovec");
 	}
 	buf->iov[pos].iov_base = NULL;
 	buf->iov[pos].iov_len = 0;
diff --git a/src/lib/small/mempool.h b/src/lib/small/mempool.h
index d465efa43c2c52d4cd851edd866e11df9b55be38..8ce0056953d9c84be0f0f55117709a8ef1d6ad99 100644
--- a/src/lib/small/mempool.h
+++ b/src/lib/small/mempool.h
@@ -65,7 +65,7 @@ extern "C" {
  * ----------------
  * The only type of failure which can occur is a failure to
  * allocate memory. In case of such error, an exception
- * (ClientError, ER_OUT_OF_RESOURCES) is raised. _nothrow()
+ * (OutOfMemory) is raised. _nothrow()
  * version of mempool_alloc() returns NULL rather than raises an
  * error in case of failure.
  */
@@ -284,8 +284,8 @@ mempool_alloc(struct mempool *pool)
 {
 	void *ptr = mempool_alloc_nothrow(pool);
 	if (ptr == NULL)
-		tnt_raise(LoggedError, ER_MEMORY_ISSUE,
-			  pool->objsize, "mempool", "new slab");
+		tnt_raise(OutOfMemory, pool->objsize,
+			  "mempool", "new slab");
 	return ptr;
 }
 
diff --git a/src/lib/small/region.h b/src/lib/small/region.h
index e06fbd4d4efff66c6c724dea160d403b839f23d4..11adb988b7ffbf0f1c4d796278568e12bfc3f4eb 100644
--- a/src/lib/small/region.h
+++ b/src/lib/small/region.h
@@ -232,8 +232,7 @@ region_alloc(struct region *region, size_t size)
 {
 	void *ptr = region_alloc_nothrow(region, size);
 	if (ptr == NULL)
-		tnt_raise(LoggedError, ER_MEMORY_ISSUE,
-			  size, "region", "new slab");
+		tnt_raise(OutOfMemory, size, "region", "new slab");
 	return ptr;
 }
 
diff --git a/src/lib/small/small.h b/src/lib/small/small.h
index 6d77797b228aa7bf3a89dd8205cddd17a97da378..2efcab7e9dcf6b4cde4b7530a9026ef1ff1aa2f6 100644
--- a/src/lib/small/small.h
+++ b/src/lib/small/small.h
@@ -277,8 +277,7 @@ smalloc(struct small_alloc *alloc, size_t size, const char *where)
 {
 	void *ptr = smalloc_nothrow(alloc, size);
 	if (ptr == NULL)
-		tnt_raise(LoggedError, ER_MEMORY_ISSUE,
-			  size, "slab allocator", where);
+		tnt_raise(OutOfMemory, size, "slab allocator", where);
 	return ptr;
 }
 
diff --git a/src/lua/fiber.cc b/src/lua/fiber.cc
index 67094fba8141a2dbf91b6bedac93042749f09627..82e6ad17527114a39fdd0ba40b68d31343c803d1 100644
--- a/src/lua/fiber.cc
+++ b/src/lua/fiber.cc
@@ -294,7 +294,10 @@ lbox_fiber_create(struct lua_State *L)
 {
 	if (lua_gettop(L) < 1 || !lua_isfunction(L, 1))
 		luaL_error(L, "fiber.create(function, ...): bad arguments");
-	fiber_checkstack();
+	if (fiber_checkstack()) {
+		lua_pushstring(L, "out of fiber stack");
+		tnt_raise(LuajitError, L);
+	}
 
 	struct fiber *f = fiber_new("lua", box_lua_fiber_run);
 	/* Not a system fiber. */
diff --git a/src/lua/init.cc b/src/lua/init.cc
index 7a39e454b74f91d309c49e3dc87283f63141078c..f01a95f5921bd48018b2ee0a2a48bb069f40d02e 100644
--- a/src/lua/init.cc
+++ b/src/lua/init.cc
@@ -414,7 +414,7 @@ run_script(va_list ap)
 	}
 	try {
 		lbox_call(L, lua_gettop(L) - 1, 0);
-	} catch (ClientError *e) {
+	} catch (Exception *e) {
 		panic("%s", e->errmsg());
 	}
 
diff --git a/src/lua/trigger.cc b/src/lua/trigger.cc
index 3fafdd1cc42a1ab61f483dfb33f868f3310445c7..a3bd8303ed135dfbb6d432f978c647a0402bb26a 100644
--- a/src/lua/trigger.cc
+++ b/src/lua/trigger.cc
@@ -90,7 +90,7 @@ lbox_trigger_reset(struct lua_State *L, int top,
 		luaL_unref(L, LUA_REGISTRYINDEX, (intptr_t) trg->data);
 
 	} else if (lua_isfunction(L, top)) {
-		tnt_raise(ClientError, ER_NO_SUCH_TRIGGER);
+		luaL_error(L, "trigger reset: Trigger is not found");
 	}
 	/*
 	 * During update of a trigger, we must preserve its
diff --git a/src/lua/utils.cc b/src/lua/utils.cc
index 61f2786be6ec70ca79f08612844d5aad271f52b8..6f68a5fc2528a89fd9c5f42eece62e60e440b9c8 100644
--- a/src/lua/utils.cc
+++ b/src/lua/utils.cc
@@ -688,3 +688,11 @@ tarantool_lua_utils_init(struct lua_State *L)
 	fpconv_init();
 	return 0;
 }
+
+LuajitError::LuajitError(const char *file, unsigned line,
+			 struct lua_State *L)
+	:Exception(file, line)
+{
+	const char *msg = lua_tostring(L, -1);
+	snprintf(m_errmsg, sizeof(m_errmsg), "%s", msg ? msg : "");
+}
diff --git a/src/lua/utils.h b/src/lua/utils.h
index 055f87b11dda30c7e842fb7c74f168aa8a031599..d023c322667d642f0a8b71c5e9f18b7084417171 100644
--- a/src/lua/utils.h
+++ b/src/lua/utils.h
@@ -430,11 +430,12 @@ tarantool_lua_utils_init(struct lua_State *L);
 } /* extern "C" */
 
 #include "exception.h"
+class LuajitError: public Exception {
+public:
+	LuajitError(const char *file, unsigned line,
+		    struct lua_State *L);
+};
 
-/**
- * A wrapper around lua_call() which converts Lua error(...)
- * to ER_PROC_LUA
- */
 static inline void
 lbox_call(struct lua_State *L, int nargs, int nreturns)
 {
@@ -445,14 +446,15 @@ lbox_call(struct lua_State *L, int nargs, int nreturns)
 		throw;
 	} catch (...) {
 		/* Convert Lua error to a Tarantool exception. */
-		const char *msg = lua_tostring(L, -1);
-		tnt_raise(ClientError, ER_PROC_LUA, msg ? msg : "");
+		tnt_raise(LuajitError, L);
 	}
 }
 
 /**
  * Single global lua_State shared by core and modules.
  * Created with tarantool_lua_init().
+ * const char *msg = lua_tostring(L, -1);
+ * snprintf(m_errmsg, sizeof(m_errmsg), "%s", msg ? msg : "");
  */
 extern struct lua_State *tarantool_L;
 
diff --git a/src/pickle.h b/src/pickle.h
index 24315f945c1c8e91583d55fa7cada919d0167368..8c015b7bcab5c59ab388992f2df44f9a75ce7e36 100644
--- a/src/pickle.h
+++ b/src/pickle.h
@@ -37,7 +37,6 @@
  * tuple and iproto binary formats.
  *
  * load_* - no boundary checking
- * pick_* - throws exception if no data in the buffer
  */
 
 static inline uint32_t
@@ -48,34 +47,6 @@ load_u32(const char **data)
 	return *b;
 }
 
-#define pick_u(bits)						\
-static inline uint##bits##_t					\
-pick_u##bits(const char **begin, const char *end)		\
-{								\
-	if (end - *begin < (bits)/8)				\
-		tnt_raise(IllegalParams,			\
-			  "packet too short (expected "#bits" bits)");\
-	uint##bits##_t r = *(uint##bits##_t *)*begin;		\
-	*begin += (bits)/8;					\
-	return r;						\
-}
-
-pick_u(8)
-pick_u(16)
-pick_u(32)
-pick_u(64)
-
-static inline const char *
-pick_str(const char **data, const char *end, uint32_t size)
-{
-	const char *str = *data;
-	if (str + size > end)
-		tnt_raise(IllegalParams,
-			  "packet too short (expected a field)");
-	*data += size;
-	return str;
-}
-
 #define pack_u(bits)						\
 static inline char *						\
 pack_u##bits(char *buf, uint##bits##_t val)			\
diff --git a/test/box/session.result b/test/box/session.result
index 49e15c219637e1000144c27056902024692a4954..eb905aca726bdbc57261cc0f1ec90476343cf8bc 100644
--- a/test/box/session.result
+++ b/test/box/session.result
@@ -80,11 +80,11 @@ session.on_disconnect()
 ...
 session.on_connect(function() end, function() end)
 ---
-- error: Trigger is not found
+- error: 'trigger reset: Trigger is not found'
 ...
 session.on_disconnect(function() end, function() end)
 ---
-- error: Trigger is not found
+- error: 'trigger reset: Trigger is not found'
 ...
 session.on_connect(1, 2)
 ---
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
index 0df204d057626b048ddfba8928dc078377577bfa..1091ee26dd8b55c979b9d6c98b7e40eec19172a9 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -49,12 +49,16 @@ target_link_libraries(rtree_itr.test)
 add_executable(matras.test matras.cc)
 target_link_libraries(matras.test small)
 add_executable(vclock.test vclock.cc test.c
-    ${CMAKE_SOURCE_DIR}/src/box/vclock.c)
-target_link_libraries(vclock.test core small
-    ${LIBEV_LIBRARIES} ${LIBEIO_LIBRARIES} ${LIBCORO_LIBRARIES})
+    ${CMAKE_SOURCE_DIR}/src/box/vclock.c
+    ${CMAKE_SOURCE_DIR}/src/box/errcode.c
+    ${CMAKE_SOURCE_DIR}/src/box/error.cc)
+target_link_libraries(vclock.test core small)
 add_executable(quota.test quota.cc test.c)
 target_link_libraries(quota.test pthread)
 
+add_executable(fiber.test fiber.cc)
+target_link_libraries(fiber.test core)
+
 set(MSGPUCK_DIR ${PROJECT_SOURCE_DIR}/src/lib/msgpuck/)
 add_executable(msgpack.test
     ${MSGPUCK_DIR}/test/msgpuck.c
diff --git a/test/unit/fiber.cc b/test/unit/fiber.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d851007323f5f00a8555ae3d7ca74c0d591a0947
--- /dev/null
+++ b/test/unit/fiber.cc
@@ -0,0 +1,10 @@
+#include "memory.h"
+#include "fiber.h"
+int main()
+{
+	memory_init();
+	fiber_init();
+	fiber_free();
+	memory_free();
+	return 0;
+}
diff --git a/test/unit/fiber.result b/test/unit/fiber.result
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391