diff --git a/src/box/authentication.cc b/src/box/authentication.cc
index 65a37870252f0c8060dbdd9bc8fc6b2fde59eef7..c078e55c7437e432b1e3e7f12b1ba2adc6def3b9 100644
--- a/src/box/authentication.cc
+++ b/src/box/authentication.cc
@@ -32,50 +32,73 @@
 #include "user.h"
 #include "session.h"
 #include "iproto_constants.h"
+#include "xrow.h"
 
 static char zero_hash[SCRAMBLE_SIZE];
 
-void
-auth_request_decode_xc(struct auth_request *request, uint64_t sync,
-		       const char *data, uint32_t len)
+int
+xrow_decode_auth(const struct xrow_header *row, struct auth_request *request)
 {
-	const char *end = data + len;
-	uint32_t map_size;
-	if (mp_typeof(*data) != MP_MAP || mp_check_map(data, end) > 0)
-		tnt_raise(ClientError, ER_INVALID_MSGPACK, "packet body");
+	if (row->bodycnt == 0) {
+		diag_set(ClientError, ER_INVALID_MSGPACK,
+			 "missing request body");
+		return 1;
+	}
+
+	assert(row->bodycnt == 1);
+	const char *data = (const char *) row->body[0].iov_base;
+	const char *end = data + row->body[0].iov_len;
+	assert((end - data) > 0);
+
+	if (mp_typeof(*data) != MP_MAP || mp_check_map(data, end) > 0) {
+error:
+		diag_set(ClientError, ER_INVALID_MSGPACK, "packet body");
+		return 1;
+	}
+
+	memset(request, 0, sizeof(*request));
+	request->header = row;
 
-	map_size = mp_decode_map(&data);
-	request->user_name = NULL;
-	request->scramble = NULL;
-	request->sync = sync;
+	uint32_t map_size = mp_decode_map(&data);
 	for (uint32_t i = 0; i < map_size; ++i) {
-		uint8_t key = *data;
-		if (key != IPROTO_USER_NAME && key != IPROTO_TUPLE) {
-			/* Skip key + value. */
-			mp_check(&data, end);
-			mp_check(&data, end);
-			continue;
-		}
-		const char *value = ++data;
-		if (mp_check(&data, end) != 0) {
-			tnt_raise(ClientError, ER_INVALID_MSGPACK,
-				  "packet body");
-		}
-		if (key == IPROTO_USER_NAME)
+		if ((end - data) < 1 || mp_typeof(*data) != MP_UINT)
+			goto error;
+
+		uint64_t key = mp_decode_uint(&data);
+		const char *value = data;
+		if (mp_check(&data, end) != 0)
+			goto error;
+
+		switch (key) {
+		case IPROTO_USER_NAME:
+			if (mp_typeof(*value) != MP_STR)
+				goto error;
 			request->user_name = value;
-		else
+			break;
+		case IPROTO_TUPLE:
+			if (mp_typeof(*value) != MP_ARRAY)
+				goto error;
 			request->scramble = value;
+			break;
+		default:
+			continue; /* unknown key */
+		}
+	}
+	if (data != end) {
+		diag_set(ClientError, ER_INVALID_MSGPACK, "packet end");
+		return 1;
 	}
 	if (request->user_name == NULL) {
-		tnt_raise(ClientError, ER_MISSING_REQUEST_FIELD,
+		diag_set(ClientError, ER_MISSING_REQUEST_FIELD,
 			  iproto_key_name(IPROTO_USER_NAME));
+		return 1;
 	}
 	if (request->scramble == NULL) {
-		tnt_raise(ClientError, ER_MISSING_REQUEST_FIELD,
-			  iproto_key_name(IPROTO_TUPLE));
+		diag_set(ClientError, ER_MISSING_REQUEST_FIELD,
+			 iproto_key_name(IPROTO_TUPLE));
+		return 1;
 	}
-	if (data != end)
-		tnt_raise(ClientError, ER_INVALID_MSGPACK, "packet body");
+	return 0;
 }
 
 void
diff --git a/src/box/authentication.h b/src/box/authentication.h
index 6989628a3b6a037d4705463ec7ca84f87a7864d9..1cf9d6d8737da94ae47b28db5253a6c7e26f111d 100644
--- a/src/box/authentication.h
+++ b/src/box/authentication.h
@@ -33,29 +33,37 @@
 
 #include <stdint.h>
 
-/** Auth request details. */
+#if defined(__cplusplus)
+extern "C" {
+#endif /* defined(__cplusplus) */
+
+struct xrow_header;
+
+/**
+ * AUTH request
+ */
 struct auth_request {
-	/**
-	 * MessagePack encoded name of the user to
-	 * authenticate.
-	 */
+	/** Request header */
+	const struct xrow_header *header;
+	/** MessagePack encoded name of the user to authenticate. */
 	const char *user_name;
 	/** Auth scramble. @sa scramble.h */
 	const char *scramble;
-	/** Request sync. */
-	uint64_t sync;
 };
 
 /**
- * Decode auth request from MessagePack.
- * @param[out] request Request to decode to.
- * @param sync Request sync.
- * @param data Request MessagePack body.
- * @param len @data length.
+ * Decode AUTH request from MessagePack.
+ * @param row request header.
+ * @param[out] request Request to decode.
+ * @retval  0 on success
+ * @retval -1 on error
  */
-void
-auth_request_decode_xc(struct auth_request *request, uint64_t sync,
-		       const char *data, uint32_t len);
+int
+xrow_decode_auth(const struct xrow_header *row, struct auth_request *request);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif /* defined(__cplusplus) */
 
 void
 authenticate(const char *user_name, uint32_t len, const char *tuple);
diff --git a/src/box/box.cc b/src/box/box.cc
index 67c925afc991b6bf4478d44689b51a4d6d00d2ca..3b29ad7f05b563094725afb7f969ae1b5306a71e 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -961,7 +961,7 @@ box_process_auth(struct auth_request *request, struct obuf *out)
 	const char *user = request->user_name;
 	uint32_t len = mp_decode_strl(&user);
 	authenticate(user, len, request->scramble);
-	iproto_reply_ok_xc(out, request->sync, ::schema_version);
+	iproto_reply_ok_xc(out, request->header->sync, ::schema_version);
 }
 
 void
diff --git a/src/box/call.cc b/src/box/call.cc
index c6fd46c36d166cdcce70e76ccd47e67c65fc466b..59b0d66f56d5c6c115533b3f3a8bb9129ce10a3e 100644
--- a/src/box/call.cc
+++ b/src/box/call.cc
@@ -45,67 +45,82 @@
 
 static const char empty_args[] = { (char)0x90 };
 
-void
-call_request_decode_xc(struct call_request *request, uint8_t type,
-		       uint64_t sync, const char *data, uint32_t len)
+int
+xrow_decode_call(const struct xrow_header *row, struct call_request *request)
 {
-	assert(type == IPROTO_CALL || type == IPROTO_CALL_16 || type == IPROTO_EVAL);
-	const char *end = data + len;
-	uint32_t map_size;
-	if (mp_typeof(*data) != MP_MAP || mp_check_map(data, end) > 0)
-		tnt_raise(ClientError, ER_INVALID_MSGPACK, "packet body");
+	if (row->bodycnt == 0) {
+		diag_set(ClientError, ER_INVALID_MSGPACK,
+			 "missing request body");
+		return 1;
+	}
+
+	assert(row->bodycnt == 1);
+	const char *data = (const char *) row->body[0].iov_base;
+	const char *end = data + row->body[0].iov_len;
+	assert((end - data) > 0);
+
+	if (mp_typeof(*data) != MP_MAP || mp_check_map(data, end) > 0) {
+error:
+		diag_set(ClientError, ER_INVALID_MSGPACK, "packet body");
+		return 1;
+	}
 
-	map_size = mp_decode_map(&data);
-	request->name = NULL;
-	request->args = NULL;
-	request->args_end = NULL;
-	request->type = type;
-	request->sync = sync;
+	memset(request, 0, sizeof(*request));
+	request->header = row;
+
+	uint32_t map_size = mp_decode_map(&data);
 	for (uint32_t i = 0; i < map_size; ++i) {
-		uint8_t key = *data;
-		if (key != IPROTO_EXPR && key != IPROTO_FUNCTION_NAME &&
-		    key != IPROTO_TUPLE) {
-			/* Skip key + value. */
-			mp_check(&data, end);
-			mp_check(&data, end);
-			continue;
-		}
-		const char *value = ++data;
-		if (mp_check(&data, end) != 0) {
-			tnt_raise(ClientError, ER_INVALID_MSGPACK,
-				  "packet body");
-		}
-		switch(key) {
-		case IPROTO_EXPR:
-			request->expr = value;
-			break;
+		if ((end - data) < 1 || mp_typeof(*data) != MP_UINT)
+			goto error;
+
+		uint64_t key = mp_decode_uint(&data);
+		const char *value = data;
+		if (mp_check(&data, end) != 0)
+			goto error;
+
+		switch (key) {
 		case IPROTO_FUNCTION_NAME:
+			if (mp_typeof(*value) != MP_STR)
+				goto error;
 			request->name = value;
 			break;
+		case IPROTO_EXPR:
+			if (mp_typeof(*value) != MP_STR)
+				goto error;
+			request->expr = value;
+			break;
 		case IPROTO_TUPLE:
+			if (mp_typeof(*value) != MP_ARRAY)
+				goto error;
 			request->args = value;
 			request->args_end = data;
 			break;
 		default:
-			unreachable();
+			continue; /* unknown key */
 		}
 	}
-	if (type == IPROTO_EVAL) {
+	if (data != end) {
+		diag_set(ClientError, ER_INVALID_MSGPACK, "packet end");
+		return 1;
+	}
+	if (row->type == IPROTO_EVAL) {
 		if (request->expr == NULL) {
-			tnt_raise(ClientError, ER_MISSING_REQUEST_FIELD,
-				  iproto_key_name(IPROTO_EXPR));
+			diag_set(ClientError, ER_MISSING_REQUEST_FIELD,
+				 iproto_key_name(IPROTO_EXPR));
+			return 1;
 		}
 	} else if (request->name == NULL) {
-		assert(type == IPROTO_CALL_16 || type == IPROTO_CALL);
-		tnt_raise(ClientError, ER_MISSING_REQUEST_FIELD,
-			  iproto_key_name(IPROTO_FUNCTION_NAME));
+		assert(row->type == IPROTO_CALL_16 ||
+		       row->type == IPROTO_CALL);
+		diag_set(ClientError, ER_MISSING_REQUEST_FIELD,
+			 iproto_key_name(IPROTO_FUNCTION_NAME));
+		return 1;
 	}
 	if (request->args == NULL) {
 		request->args = empty_args;
 		request->args_end = empty_args + sizeof(empty_args);
 	}
-	if (data != end)
-		tnt_raise(ClientError, ER_INVALID_MSGPACK, "packet body");
+	return 0;
 }
 
 static inline struct func *
@@ -164,16 +179,16 @@ func_call(struct func *func, struct call_request *request, struct obuf *out)
 	if (iproto_prepare_select(out, &svp) != 0)
 		goto error;
 
-	if (request->type == IPROTO_CALL_16) {
+	if (request->header->type == IPROTO_CALL_16) {
 		/* Tarantool < 1.7.1 compatibility */
 		if (port_dump(&port, out) != 0) {
 			obuf_rollback_to_svp(out, &svp);
 			goto error;
 		}
-		iproto_reply_select(out, &svp, request->sync,
+		iproto_reply_select(out, &svp, request->header->sync,
 				    ::schema_version, port.size);
 	} else {
-		assert(request->type == IPROTO_CALL);
+		assert(request->header->type == IPROTO_CALL);
 		char *size_buf = (char *)
 			obuf_alloc(out, mp_sizeof_array(port.size));
 		if (size_buf == NULL)
@@ -183,7 +198,7 @@ func_call(struct func *func, struct call_request *request, struct obuf *out)
 			obuf_rollback_to_svp(out, &svp);
 			goto error;
 		}
-		iproto_reply_select(out, &svp, request->sync,
+		iproto_reply_select(out, &svp, request->header->sync,
 				    ::schema_version, 1);
 	}
 
diff --git a/src/box/call.h b/src/box/call.h
index 1c1cc6c4ba44072d404ceac27f87c5d6cef58e08..fd0e4ca28511950b80f340e95e17029bcfd8edfb 100644
--- a/src/box/call.h
+++ b/src/box/call.h
@@ -33,43 +33,46 @@
 
 #include <stdint.h>
 
-struct obuf;
+#if defined(__cplusplus)
+extern "C" {
+#endif /* defined(__cplusplus) */
 
-/** Request details of call and eval. */
+/**
+ * CALL/EVAL request.
+ */
 struct call_request {
-	/**
-	 * Set either name to function name of call request or
-	 * set expr to lua expression for eval request.
-	 */
-	union {
-		const char *name;
-		const char *expr;
-	};
-	/** Call/eval parameters. */
+	/** Request header */
+	const struct xrow_header *header;
+	/** Function name for CALL request. MessagePack String. */
+	const char *name;
+	/** Expression for EVAL request. MessagePack String. */
+	const char *expr;
+	/** CALL/EVAL parameters. MessagePack Array. */
 	const char *args;
 	const char *args_end;
-	/** IPROTO_CALL/IPROTO_CALL_16/IPROTO_EVAL */
-	uint8_t type;
-	/** Request sync. @sa xrow_header. */
-	uint64_t sync;
-};
-
-struct box_function_ctx {
-	struct call_request *request;
-	struct port *port;
 };
 
 /**
- * Decode call request from a given MessagePack map.
+ * Decode CALL/EVAL request from a given MessagePack map.
  * @param[out] call_request Request to decode to.
  * @param type Request type - either CALL or CALL_16 or EVAL.
  * @param sync Request sync.
  * @param data Request MessagePack encoded body.
  * @param len @data length.
  */
-void
-call_request_decode_xc(struct call_request *request, uint8_t type,
-		       uint64_t sync, const char *data, uint32_t len);
+int
+xrow_decode_call(const struct xrow_header *row, struct call_request *request);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif /* defined(__cplusplus) */
+
+struct obuf;
+
+struct box_function_ctx {
+	struct call_request *request;
+	struct port *port;
+};
 
 void
 box_process_call(struct call_request *request, struct obuf *out);
diff --git a/src/box/iproto.cc b/src/box/iproto.cc
index 819669910b2a05934e179c90f2de5d09659a5a74..7f14fc648def037c76eebc82e238cde2eb57b2aa 100644
--- a/src/box/iproto.cc
+++ b/src/box/iproto.cc
@@ -620,7 +620,6 @@ iproto_decode_msg(struct iproto_msg *msg, const char **pos, const char *reqend,
 	assert(*pos == reqend);
 	const char *body;
 	uint8_t type = msg->header.type;
-	uint64_t sync = msg->header.sync;
 
 	switch (type) {
 	case IPROTO_SELECT:
@@ -650,11 +649,8 @@ iproto_decode_msg(struct iproto_msg *msg, const char **pos, const char *reqend,
 	case IPROTO_CALL_16:
 	case IPROTO_CALL:
 	case IPROTO_EVAL:
-		if (msg->header.bodycnt == 0)
-			goto err_no_body;
-		body = (const char *) msg->header.body[0].iov_base;
-		call_request_decode_xc(&msg->call_request, type, sync, body,
-				       msg->header.body[0].iov_len);
+		if (xrow_decode_call(&msg->header, &msg->call_request) != 0)
+			diag_raise();
 		cmsg_init(msg, misc_route);
 		break;
 	case IPROTO_PING:
@@ -666,11 +662,8 @@ iproto_decode_msg(struct iproto_msg *msg, const char **pos, const char *reqend,
 		*stop_input = true;
 		break;
 	case IPROTO_AUTH:
-		if (msg->header.bodycnt == 0)
-			goto err_no_body;
-		body = (const char *) msg->header.body[0].iov_base;
-		auth_request_decode_xc(&msg->auth_request, sync, body,
-				       msg->header.body[0].iov_len);
+		if (xrow_decode_auth(&msg->header, &msg->auth_request) != 0)
+			diag_raise();
 		cmsg_init(msg, misc_route);
 		break;
 	default:
@@ -1034,11 +1027,9 @@ tx_process_misc(struct cmsg *m)
 		switch (msg->header.type) {
 		case IPROTO_CALL:
 		case IPROTO_CALL_16:
-			assert(msg->call_request.type == msg->header.type);
 			box_process_call(&msg->call_request, out);
 			break;
 		case IPROTO_EVAL:
-			assert(msg->call_request.type == msg->header.type);
 			box_process_eval(&msg->call_request, out);
 			break;
 		case IPROTO_AUTH:
diff --git a/src/box/lua/call.c b/src/box/lua/call.c
index 62fc549b5d0a4237cc8318d173b56c6ec36af86e..f0bc7863deb056f2ec3a6580ebaa17b9058ccf02 100644
--- a/src/box/lua/call.c
+++ b/src/box/lua/call.c
@@ -311,11 +311,11 @@ execute_lua_call(lua_State *L)
 		      luamp_error, L);
 
 	int count;
-	if (request->type == IPROTO_CALL_16) {
+	if (request->header->type == IPROTO_CALL_16) {
 		/* Tarantool < 1.7.1 compatibility */
 		count = luamp_encode_call(L, cfg, &stream);
 	} else {
-		assert(request->type == IPROTO_CALL);
+		assert(request->header->type == IPROTO_CALL);
 		count = lua_gettop(L);
 		for (int k = 1; k <= count; ++k) {
 			luamp_encode(L, cfg, &stream, k);
@@ -323,7 +323,8 @@ execute_lua_call(lua_State *L)
 	}
 
 	mpstream_flush(&stream);
-	iproto_reply_select(out, svp, request->sync, schema_version, count);
+	iproto_reply_select(out, svp, request->header->sync, schema_version,
+			    count);
 	return 0; /* truncate Lua stack */
 }
 
@@ -368,7 +369,8 @@ execute_lua_eval(lua_State *L)
 		luamp_encode(L, luaL_msgpack_default, &stream, k);
 	}
 	mpstream_flush(&stream);
-	iproto_reply_select(out, svp, request->sync, schema_version, nrets);
+	iproto_reply_select(out, svp, request->header->sync, schema_version,
+			    nrets);
 
 	return 0;
 }