diff --git a/src/box/box.cc b/src/box/box.cc
index 6256663de517b39913079640ff0813b4aafbb93e..79721a2e633b066aba18c1b94304a6eb257bd6e3 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -878,7 +878,7 @@ box_load_cfg()
 		box_init();
 	} catch (Exception *e) {
 		e->log();
-		panic("can't initialize storage: %s", e->errmsg());
+		panic("can't initialize storage: %s", e->get_errmsg());
 	}
 }
 
diff --git a/src/box/error.cc b/src/box/error.cc
index 9b0f92068ef6e14a6aa880df5f2a56bff4e3a3ad..56b319c7edda91d5833c47339a12864f7e309c32 100644
--- a/src/box/error.cc
+++ b/src/box/error.cc
@@ -52,11 +52,10 @@ ClientError::ClientError(const char *file, unsigned line,
 	m_errcode = errcode;
 	va_list ap;
 	va_start(ap, errcode);
-	vsnprintf(m_errmsg, sizeof(m_errmsg),
-		  tnt_errcode_desc(m_errcode), ap);
+	error_vformat_msg(this, tnt_errcode_desc(m_errcode), ap);
+	va_end(ap);
 	if (rmean_error)
 		rmean_collect(rmean_error, RMEAN_ERROR, 1);
-	va_end(ap);
 }
 
 ClientError::ClientError(const char *file, unsigned line, const char *msg,
@@ -64,8 +63,7 @@ ClientError::ClientError(const char *file, unsigned line, const char *msg,
 	: Exception(&type_ClientError, file, line)
 {
 	m_errcode = errcode;
-	strncpy(m_errmsg, msg, sizeof(m_errmsg) - 1);
-	m_errmsg[sizeof(m_errmsg) - 1] = 0;
+	error_format_msg(this, "%s", msg);
 	if (rmean_error)
 		rmean_collect(rmean_error, RMEAN_ERROR, 1);
 }
@@ -73,7 +71,7 @@ ClientError::ClientError(const char *file, unsigned line, const char *msg,
 void
 ClientError::log() const
 {
-	_say(S_ERROR, m_file, m_line, m_errmsg, "%s", tnt_errcode_str(m_errcode));
+	_say(S_ERROR, file, line, errmsg, "%s", tnt_errcode_str(m_errcode));
 }
 
 
@@ -95,9 +93,8 @@ ErrorInjection::ErrorInjection(const char *file, unsigned line, const char *msg)
 }
 
 const char *
-box_error_type(const box_error_t *error)
+box_error_type(const box_error_t *e)
 {
-	Exception *e = (Exception *) error;
 	return e->type->name;
 }
 
@@ -111,14 +108,13 @@ box_error_code(const box_error_t *error)
 const char *
 box_error_message(const box_error_t *error)
 {
-	Exception *e = (Exception *) error;
-	return e->errmsg();
+	return error->errmsg;
 }
 
 const box_error_t *
 box_error_last(void)
 {
-	return (box_error_t *) diag_last_error(&fiber()->diag);
+	return diag_last_error(&fiber()->diag);
 }
 
 void
diff --git a/src/box/error.h b/src/box/error.h
index 40dccfeee8580f8e9ec37a14253fd39ced8b0229..d7dc50d2974b6c94dc2aa3184c983ec14e9e9c45 100644
--- a/src/box/error.h
+++ b/src/box/error.h
@@ -96,11 +96,11 @@ class ErrorInjection: public LoggedError {
 
 /** \cond public */
 
-struct diag_msg;
+struct error;
 /**
  * Error - contains information about error.
  */
-typedef struct diag_msg box_error_t;
+typedef struct error box_error_t;
 
 /**
  * Return the error type, e.g. "ClientError", "SocketError", etc.
diff --git a/src/box/iproto_port.cc b/src/box/iproto_port.cc
index bdacd141cbedd686f33d0288c7fb6c0948b3bab7..2f07732855d9adc1d53172c96f6f6751ff5989b5 100644
--- a/src/box/iproto_port.cc
+++ b/src/box/iproto_port.cc
@@ -84,7 +84,7 @@ iproto_reply_ok(struct obuf *out, uint64_t sync)
 void
 iproto_reply_error(struct obuf *out, const Exception *e, uint64_t sync)
 {
-	uint32_t msg_len = strlen(e->errmsg());
+	uint32_t msg_len = strlen(e->get_errmsg());
 	uint32_t errcode = ClientError::get_errcode(e);
 
 	struct iproto_header_bin header = iproto_header_bin;
@@ -99,7 +99,7 @@ iproto_reply_error(struct obuf *out, const Exception *e, uint64_t sync)
 
 	obuf_dup(out, &header, sizeof(header));
 	obuf_dup(out, &body, sizeof(body));
-	obuf_dup(out, e->errmsg(), msg_len);
+	obuf_dup(out, e->get_errmsg(), msg_len);
 }
 
 static inline struct iproto_port *
diff --git a/src/box/lua/info.cc b/src/box/lua/info.cc
index c75189808690aa9b751f1a6096356eba3106fe82..36708b883f3a23210763d3ff0cce87af6cae073a 100644
--- a/src/box/lua/info.cc
+++ b/src/box/lua/info.cc
@@ -80,11 +80,10 @@ lbox_info_replication(struct lua_State *L)
 		lua_pushnumber(L, ev_now(loop()) - applier->last_row_time);
 		lua_settable(L, -3);
 
-		Exception *e = (Exception *)
-			diag_last_error(&applier->reader->diag);
+		struct error *e = diag_last_error(&applier->reader->diag);
 		if (e != NULL) {
 			lua_pushstring(L, "message");
-			lua_pushstring(L, e->errmsg());
+			lua_pushstring(L, e->errmsg);
 			lua_settable(L, -3);
 		}
 	}
diff --git a/src/box/memtx_engine.cc b/src/box/memtx_engine.cc
index f4d5bc5a44a15d3598cc9cebe62741ff007a0823..7ebe7955679efa37849a1693a3bc52d3b192611d 100644
--- a/src/box/memtx_engine.cc
+++ b/src/box/memtx_engine.cc
@@ -1122,7 +1122,7 @@ MemtxEngine::waitCheckpoint()
 		result = -1;
 		SystemError *se = type_cast(SystemError, e);
 		if (se)
-			errno = se->errnum();
+			errno = se->get_errno();
 	}
 
 	m_checkpoint->waiting_for_snap_thread = false;
diff --git a/src/box/xlog.cc b/src/box/xlog.cc
index 6ee2d73ea0e64864792b0ea4caa40d1d4777304d..cb6cf5e0c4dc528ada3a365529697743f6e37d46 100644
--- a/src/box/xlog.cc
+++ b/src/box/xlog.cc
@@ -63,7 +63,7 @@ XlogError::XlogError(const char *file, unsigned line,
 {
 	va_list ap;
 	va_start(ap, format);
-	vsnprintf(m_errmsg, sizeof(m_errmsg), format, ap);
+	error_vformat_msg(this, format, ap);
 	va_end(ap);
 }
 
@@ -73,7 +73,7 @@ XlogError::XlogError(const struct type *type, const char *file, unsigned line,
 {
 	va_list ap;
 	va_start(ap, format);
-	vsnprintf(m_errmsg, sizeof(m_errmsg), format, ap);
+	error_vformat_msg(this, format, ap);
 	va_end(ap);
 }
 
@@ -87,7 +87,7 @@ XlogGapError::XlogGapError(const char *file, unsigned line,
 {
 	char *s_from = vclock_to_string(from);
 	char *s_to = vclock_to_string(to);
-	snprintf(m_errmsg, sizeof(m_errmsg),
+	snprintf(errmsg, sizeof(errmsg),
 		 "Missing .xlog file between LSN %lld %s and %lld %s",
 		 (long long) vclock_sum(from), s_from ? s_from : "",
 		 (long long) vclock_sum(to), s_to ? s_to : "");
diff --git a/src/diag.c b/src/diag.c
index c72f736d8d68033af3521d344e13a24a19bbe510..9477087a163000c86c4bd2f35a8d54a8cf015285 100644
--- a/src/diag.c
+++ b/src/diag.c
@@ -32,13 +32,23 @@
 #include "fiber.h"
 
 void
-diag_msg_create(struct diag_msg *msg,
-		void (*destroy)(struct diag_msg *),
-		const struct type *type)
+error_create(struct error *e,
+	     void (*destroy)(struct error *),
+	     const struct type *type,
+	     const char *file,
+	     unsigned line)
 {
-	msg->destroy = destroy;
-	msg->type = type;
-	msg->refs = 0;
+	e->destroy = destroy;
+	e->type = type;
+	e->refs = 0;
+	if (file != NULL) {
+		snprintf(e->file, sizeof(e->file), "%s", file);
+		e->line = line;
+	} else {
+		e->file[0] = '\0';
+		e->line = 0;
+	}
+	e->errmsg[0] = '\0';
 }
 
 struct diag *
@@ -47,3 +57,18 @@ diag_get()
 	return &fiber()->diag;
 }
 
+void
+error_format_msg(struct error *e, const char *format, ...)
+{
+	va_list ap;
+	va_start(ap, format);
+	error_vformat_msg(e, format, ap);
+	va_end(ap);
+}
+
+void
+error_vformat_msg(struct error *e, const char *format, va_list ap)
+{
+	vsnprintf(e->errmsg, sizeof(e->errmsg), format, ap);
+}
+
diff --git a/src/diag.h b/src/diag.h
index 7427aa1bd459d66981e4218733fe33b35288fc04..39bcdf15916984fb2c0d87043d32d96505503382 100644
--- a/src/diag.h
+++ b/src/diag.h
@@ -51,47 +51,61 @@ struct type;
  * code. This is why there is a common infrastructure for errors.
  *
  * Any error or warning or note is represented by an instance of
- * struct diag_msg.
+ * struct error.
  *
- * struct diag_msg has the most common members, but more
+ * struct error has the most common members, but more
  * importantly it has a type descriptor, which makes it possible
  * to work with C++ exceptions and extra members via reflection,
  * in pure C.
  *
  * (destroy) is there to gracefully delete C++ exceptions from C.
  */
-struct diag_msg {
-	void (*destroy)(struct diag_msg *msg);
+struct error {
+	void (*destroy)(struct error *e);
 	const struct type *type;
 	int refs;
+	/** Line number. */
+	unsigned line;
+	/* Source file name. */
+	char file[DIAG_FILENAME_MAX];
+	/* Error description. */
+	char errmsg[DIAG_ERRMSG_MAX];
 };
 
 static inline void
-diag_msg_ref(struct diag_msg *msg)
+error_ref(struct error *e)
 {
-	msg->refs++;
+	e->refs++;
 }
 
 static inline void
-diag_msg_unref(struct diag_msg *msg)
+error_unref(struct error *e)
 {
-	assert(msg->refs > 0);
-	--msg->refs;
-	if (msg->refs == 0)
-		msg->destroy(msg);
+	assert(e->refs > 0);
+	--e->refs;
+	if (e->refs == 0)
+		e->destroy(e);
 }
 
 void
-diag_msg_create(struct diag_msg *msg,
-		void (*destroy)(struct diag_msg *msg),
-		const struct type *type);
+error_create(struct error *e,
+	     void (*destroy)(struct error *e),
+	     const struct type *type,
+	     const char *file,
+	     unsigned line);
+
+void
+error_format_msg(struct error *e, const char *format, ...);
+
+void
+error_vformat_msg(struct error *e, const char *format, va_list ap);
 
 /**
  * Diagnostics Area - a container for errors
  */
 struct diag {
 	/* \cond private */
-	struct diag_msg *last;
+	struct error *last;
 	/* \endcond private */
 };
 
@@ -123,7 +137,7 @@ diag_clear(struct diag *diag)
 {
 	if (diag->last == NULL)
 		return;
-	diag_msg_unref(diag->last);
+	error_unref(diag->last);
 	diag->last = NULL;
 }
 
@@ -133,10 +147,10 @@ diag_clear(struct diag *diag)
  * \param e error to add
  */
 static inline void
-diag_add_error(struct diag *diag, struct diag_msg *e)
+diag_add_error(struct diag *diag, struct error *e)
 {
 	assert(e != NULL);
-	diag_msg_ref(e);
+	error_ref(e);
 	diag_clear(diag);
 	diag->last = e;
 }
@@ -172,7 +186,7 @@ diag_destroy(struct diag *diag)
  * \return last error
  * \param diag diagnostics area
  */
-static inline struct diag_msg *
+static inline struct error *
 diag_last_error(struct diag *diag)
 {
 	return diag->last;
diff --git a/src/evio.cc b/src/evio.cc
index c12dc8f3113111461df4acc12f099ea3b9079028..337a4c72d4e3b1312601dbe149548d19cf8aa54c 100644
--- a/src/evio.cc
+++ b/src/evio.cc
@@ -262,7 +262,7 @@ evio_service_bind_and_listen(struct evio_service *service)
 			say_error("%s: failed to bind on %s: %s",
 				  evio_service_name(service),
 				  sio_strfaddr(ai->ai_addr, ai->ai_addrlen),
-				  e->errmsg());
+				  e->get_errmsg());
 			/* ignore */
 		}
 	}
diff --git a/src/exception.cc b/src/exception.cc
index e31504f0b666bb792566cecfa8477cef3f9ed74e..9659942886c2a76fabe964b850b24bdf493e11d2 100644
--- a/src/exception.cc
+++ b/src/exception.cc
@@ -40,9 +40,9 @@ static OutOfMemory out_of_memory(__FILE__, __LINE__,
 				 sizeof(OutOfMemory), "malloc", "exception");
 
 static const struct method exception_methods[] = {
-	make_method(&type_Exception, "message", &Exception::errmsg),
-	make_method(&type_Exception, "file", &Exception::file),
-	make_method(&type_Exception, "line", &Exception::line),
+	make_method(&type_Exception, "message", &Exception::get_errmsg),
+	make_method(&type_Exception, "file", &Exception::get_file),
+	make_method(&type_Exception, "line", &Exception::get_line),
 	make_method(&type_Exception, "log", &Exception::log),
 	METHODS_SENTINEL
 };
@@ -73,7 +73,7 @@ Exception::~Exception()
 }
 
 extern "C" void
-exception_destroy(struct diag_msg *msg)
+exception_destroy(struct error *msg)
 {
 	delete (Exception *) msg;
 }
@@ -81,15 +81,8 @@ exception_destroy(struct diag_msg *msg)
 Exception::Exception(const struct type *type_arg, const char *file,
 		     unsigned line)
 {
-	diag_msg_create(this, exception_destroy, type_arg);
-	if (file != NULL) {
-		snprintf(m_file, sizeof(m_file), "%s", file);
-		m_line = line;
-	} else {
-		m_file[0] = '\0';
-		m_line = 0;
-	}
-	m_errmsg[0] = '\0';
+	error_create(this, exception_destroy, type_arg,
+		     file, line);
 	if (this == &out_of_memory) {
 		/* A special workaround for out_of_memory static init */
 		out_of_memory.refs = 1;
@@ -100,11 +93,11 @@ Exception::Exception(const struct type *type_arg, const char *file,
 void
 Exception::log() const
 {
-	_say(S_ERROR, m_file, m_line, m_errmsg, "%s", type->name);
+	_say(S_ERROR, file, line, errmsg, "%s", type->name);
 }
 
 static const struct method systemerror_methods[] = {
-	make_method(&type_SystemError, "errnum", &SystemError::errnum),
+	make_method(&type_SystemError, "errno", &SystemError::get_errno),
 	METHODS_SENTINEL
 };
 
@@ -126,30 +119,15 @@ SystemError::SystemError(const char *file, unsigned line,
 {
 	va_list ap;
 	va_start(ap, format);
-	init(format, ap);
-	va_end(ap);
-}
-
-void
-SystemError::init(const char *format, ...)
-{
-	va_list ap;
-	va_start(ap, format);
-	init(format, ap);
+	error_vformat_msg(this, format, ap);
 	va_end(ap);
 }
 
-void
-SystemError::init(const char *format, va_list ap)
-{
-	vsnprintf(m_errmsg, sizeof(m_errmsg), format, ap);
-}
-
 void
 SystemError::log() const
 {
-	_say(S_SYSERROR, m_file, m_line, strerror(m_errno), "SystemError %s",
-	     m_errmsg);
+	_say(S_SYSERROR, file, line, strerror(m_errno), "SystemError %s",
+	     errmsg);
 }
 
 const struct type type_OutOfMemory =
@@ -161,9 +139,8 @@ OutOfMemory::OutOfMemory(const char *file, unsigned line,
 	: SystemError(&type_OutOfMemory, file, line)
 {
 	m_errno = ENOMEM;
-	snprintf(m_errmsg, sizeof(m_errmsg),
-		 "Failed to allocate %u bytes in %s for %s",
-		 (unsigned) amount, allocator, object);
+	error_format_msg(this, "Failed to allocate %u bytes in %s for %s",
+			 (unsigned) amount, allocator, object);
 }
 
 const struct type type_TimedOut =
diff --git a/src/exception.h b/src/exception.h
index 045f9eec88106492827e1c1f4141dd290a524ec3..9ba9219965a592703b3997a6e5fa640de13e07b5 100644
--- a/src/exception.h
+++ b/src/exception.h
@@ -39,26 +39,16 @@
 
 extern const struct type type_Exception;
 
-class Exception: public diag_msg {
+class Exception: public error {
 public:
 	void *operator new(size_t size);
 	void operator delete(void*);
-	virtual void raise() = 0;
-
-	const char *
-	errmsg() const
-	{
-		return m_errmsg;
-	}
-
-	const char *file() const {
-		return m_file;
-	}
 
-	int line() const {
-		return m_line;
-	}
+	const char *get_file() const { return file; }
+	int get_line() const { return line; }
+	const char *get_errmsg() const { return errmsg; }
 
+	virtual void raise() = 0;
 	virtual void log() const;
 	virtual ~Exception();
 
@@ -66,27 +56,14 @@ class Exception: public diag_msg {
 	Exception& operator=(const Exception&) = delete;
 protected:
 	Exception(const struct type *type, const char *file, unsigned line);
-
-	/* line number */
-	unsigned m_line;
-	/* file name */
-	char m_file[DIAG_FILENAME_MAX];
-
-	/* error description */
-	char m_errmsg[DIAG_ERRMSG_MAX];
 };
 
 extern const struct type type_SystemError;
 class SystemError: public Exception {
 public:
-
 	virtual void raise() { throw this; }
 
-	int
-	errnum() const
-	{
-		return m_errno;
-	}
+	int get_errno() const { return m_errno; }
 
 	virtual void log() const;
 
@@ -94,13 +71,6 @@ class SystemError: public Exception {
 		    const char *format, ...);
 protected:
 	SystemError(const struct type *type, const char *file, unsigned line);
-
-	void
-	init(const char *format, ...);
-
-	void
-	init(const char *format, va_list ap);
-
 protected:
 	/* system errno */
 	int m_errno;
diff --git a/src/ffisyms.cc b/src/ffisyms.cc
index 5ec554840ad7bf4b5a7d58747290450b56eca55c..df42c79ab67ccbfc1b17d37ee469c4569b74e375 100644
--- a/src/ffisyms.cc
+++ b/src/ffisyms.cc
@@ -59,7 +59,6 @@ void *ffi_symbols[] = {
 	(void *) box_iterator_next,
 	(void *) boxffi_tuple_update,
 	(void *) password_prepare,
-	(void *) tarantool_error_message,
 	(void *) load_cfg,
 	(void *) box_set_listen,
 	(void *) box_set_replication_source,
diff --git a/src/fiber.cc b/src/fiber.cc
index af5e3a6fe78152aa8e9cad64405ff83549c1a3df..d1f0f361c0831c178a827a7f6f40913bcd51fff3 100644
--- a/src/fiber.cc
+++ b/src/fiber.cc
@@ -215,7 +215,7 @@ fiber_join(struct fiber *fiber)
 
 	/* Move exception to the caller */
 	diag_move(&fiber->diag, &fiber()->diag);
-	Exception *e = (Exception *) diag_last_error(&fiber()->diag);
+	struct error *e = diag_last_error(&fiber()->diag);
 	/** Don't bother with propagation of FiberCancelException */
 	if (e != NULL && type_cast(FiberCancelException, e) != NULL)
 		diag_clear(&fiber()->diag);
diff --git a/src/lua/init.cc b/src/lua/init.cc
index ab25b2ef100244e3ead82002ddb4eb772d955f93..7c15718f9a3c8fadbc460d352354b85f38d91fc0 100644
--- a/src/lua/init.cc
+++ b/src/lua/init.cc
@@ -446,15 +446,6 @@ tarantool_lua_slab_cache()
 	return &cord()->slabc;
 }
 
-extern "C" const char *
-tarantool_error_message(void)
-{
-	/* called only from error handler */
-	Exception *e = (Exception *) diag_last_error(&fiber()->diag);
-	assert(e != NULL);
-	return e->errmsg();
-}
-
 /**
  * Execute start-up script.
  */
@@ -498,7 +489,7 @@ run_script(va_list ap)
 			lua_pushstring(L, argv[i]);
 		lbox_call(L, lua_gettop(L) - 1, 0);
 	} catch (Exception *e) {
-		panic("%s", e->errmsg());
+		panic("%s", e->get_errmsg());
 	}
 
 	/* clear the stack from return values. */
diff --git a/src/lua/init.lua b/src/lua/init.lua
index 3568ae036ea1ed57b5dff80c6317ac0d364cc76e..ddfe26b34210779e5d3a472e77d3c669bbf52092 100644
--- a/src/lua/init.lua
+++ b/src/lua/init.lua
@@ -4,8 +4,13 @@
 
 local ffi = require('ffi')
 ffi.cdef[[
-char *
-tarantool_error_message(void);
+struct error;
+
+typedef struct error box_error_t;
+const box_error_t *
+box_error_last(void);
+const char *
+box_error_message(const box_error_t *);
 double
 tarantool_uptime(void);
 typedef int32_t pid_t;
@@ -16,7 +21,7 @@ local pcall_lua = pcall
 
 local function pcall_wrap(status, ...)
     if status == false and ... == 'C++ exception' then
-        return false, ffi.string(ffi.C.tarantool_error_message())
+        return false, ffi.string(ffi.C.box_error_message(ffi.C.box_error_last()))
     end
     return status, ...
 end
diff --git a/src/lua/utils.cc b/src/lua/utils.cc
index 8c23809dc7e4184b17ac440e30a04569d289d809..a334467e2ed9bc49f93d1e7c5a12a9a3a6366aae 100644
--- a/src/lua/utils.cc
+++ b/src/lua/utils.cc
@@ -831,5 +831,5 @@ LuajitError::LuajitError(const char *file, unsigned line,
 	: Exception(&type_LuajitError, file, line)
 {
 	const char *msg = lua_tostring(L, -1);
-	snprintf(m_errmsg, sizeof(m_errmsg), "%s", msg ? msg : "");
+	snprintf(errmsg, sizeof(errmsg), "%s", msg ? msg : "");
 }
diff --git a/src/sio.cc b/src/sio.cc
index 51e9ac10d134adb1f5c5e0e72aeed73493db1ad5..4ded0c61c5ece438fcf8e3fd9371343961ddef2c 100644
--- a/src/sio.cc
+++ b/src/sio.cc
@@ -61,9 +61,9 @@ SocketError::SocketError(const char *file, unsigned line, int fd,
 	va_list ap;
 	va_start(ap, format);
 	vsnprintf(buf, sizeof(buf), format, ap);
-	const char *socketname = sio_socketname(fd);
-	init("%s, called on %s", buf, socketname);
 	va_end(ap);
+	const char *socketname = sio_socketname(fd);
+	error_format_msg(this, "%s, called on %s", buf, socketname);
 	errno = save_errno;
 }