diff --git a/src/box/xrow.c b/src/box/xrow.c
index 38f8dc8ea7c2136ff8e1012dfdbe70d1a5cb2e61..289338b20e3168c35c05d29954338fe3ed62ff58 100644
--- a/src/box/xrow.c
+++ b/src/box/xrow.c
@@ -1712,6 +1712,11 @@ xrow_encode_vote(struct xrow_header *row)
 	row->type = IPROTO_VOTE;
 }
 
+/** Decode the remote instance's IPROTO_VOTE response body. */
+static int
+mp_decode_ballot(const char *data, const char *end,
+		 struct ballot *ballot, bool *is_empty);
+
 int
 xrow_decode_ballot(const struct xrow_header *row, struct ballot *ballot)
 {
@@ -1721,6 +1726,7 @@ xrow_decode_ballot(const struct xrow_header *row, struct ballot *ballot)
 	ballot->is_anon = false;
 	ballot->is_booted = true;
 	vclock_create(&ballot->vclock);
+	vclock_create(&ballot->gc_vclock);
 
 	if (row->bodycnt == 0)
 		goto err;
@@ -1728,8 +1734,23 @@ xrow_decode_ballot(const struct xrow_header *row, struct ballot *ballot)
 
 	const char *data = (const char *)row->body[0].iov_base;
 	const char *end = data + row->body[0].iov_len;
+
+	bool is_empty;
+	if (mp_decode_ballot(data, end, ballot, &is_empty) < 0) {
+err:
+		xrow_on_decode_err(row, ER_INVALID_MSGPACK, "packet body");
+		return -1;
+	}
+	return 0;
+}
+
+static int
+mp_decode_ballot(const char *data, const char *end,
+		 struct ballot *ballot, bool *is_empty)
+{
+	*is_empty = true;
 	if (mp_typeof(*data) != MP_MAP)
-		goto err;
+		return -1;
 
 	/* Find BALLOT key. */
 	uint32_t map_size = mp_decode_map(&data);
@@ -1757,47 +1778,51 @@ xrow_decode_ballot(const struct xrow_header *row, struct ballot *ballot)
 		switch (key) {
 		case IPROTO_BALLOT_IS_RO_CFG:
 			if (mp_typeof(*data) != MP_BOOL)
-				goto err;
+				return -1;
 			ballot->is_ro_cfg = mp_decode_bool(&data);
+			*is_empty = false;
 			break;
 		case IPROTO_BALLOT_IS_RO:
 			if (mp_typeof(*data) != MP_BOOL)
-				goto err;
+				return -1;
 			ballot->is_ro = mp_decode_bool(&data);
+			*is_empty = false;
 			break;
 		case IPROTO_BALLOT_IS_ANON:
 			if (mp_typeof(*data) != MP_BOOL)
-				goto err;
+				return -1;
 			ballot->is_anon = mp_decode_bool(&data);
+			*is_empty = false;
 			break;
 		case IPROTO_BALLOT_VCLOCK:
 			if (mp_decode_vclock_ignore0(&data,
 						     &ballot->vclock) != 0)
-				goto err;
+				return -1;
+			*is_empty = false;
 			break;
 		case IPROTO_BALLOT_GC_VCLOCK:
 			if (mp_decode_vclock_ignore0(&data,
 						     &ballot->gc_vclock) != 0)
-				goto err;
+				return -1;
+			*is_empty = false;
 			break;
 		case IPROTO_BALLOT_IS_BOOTED:
 			if (mp_typeof(*data) != MP_BOOL)
-				goto err;
+				return -1;
 			ballot->is_booted = mp_decode_bool(&data);
+			*is_empty = false;
 			break;
 		case IPROTO_BALLOT_CAN_LEAD:
 			if (mp_typeof(*data) != MP_BOOL)
-				goto err;
+				return -1;
 			ballot->can_lead = mp_decode_bool(&data);
+			*is_empty = false;
 			break;
 		default:
 			mp_next(&data);
 		}
 	}
 	return 0;
-err:
-	xrow_on_decode_err(row, ER_INVALID_MSGPACK, "packet body");
-	return -1;
 }
 
 /**