diff --git a/include/iobuf.h b/include/iobuf.h
index deaf0ffaf21d4d598db7e1a28fa17a88ab23941c..60ea3fb88ddb8cd1bce304c6c8115e829ae58b48 100644
--- a/include/iobuf.h
+++ b/include/iobuf.h
@@ -136,39 +136,39 @@ obuf_iovcnt(struct obuf *buf)
 	return buf->iov[buf->pos].iov_len > 0 ? buf->pos + 1 : buf->pos;
 }
 
+/**
+ * Output buffer savepoint. It's possible to
+ * save the current buffer state in a savepoint
+ * and roll back to the saved state at any time
+ * before iobuf_flush()
+ */
+struct obuf_svp
+{
+	size_t pos;
+	size_t iov_len;
+	size_t size;
+};
+
 /**
  * Reserve size bytes in the output buffer
  * and return a pointer to the reserved
  * data. Returns a pointer to a continuous piece of
  * memory.
  * Typical use case:
- * void *psize = obuf_book(buf, sizeof(uint32_t));
+ * struct obuf_svp svp = obuf_book(buf, sizeof(uint32_t));
  * for (...)
  *	obuf_dup(buf, ...);
  * uint32_t total = obuf_size(buf);
- * memcpy(psize, &total, sizeof(total);
+ * memcpy(obuf_svp_to_ptr(&svp), &total, sizeof(total);
  * iobuf_flush();
  */
-void *
+struct obuf_svp
 obuf_book(struct obuf *obuf, size_t size);
 
 /** Append data to the output buffer. */
 void
 obuf_dup(struct obuf *obuf, void *data, size_t size);
 
-/**
- * Output buffer savepoint. It's possible to
- * save the current buffer state in a savepoint
- * and roll back to the saved state at any time
- * before iobuf_flush()
- */
-struct obuf_svp
-{
-	size_t pos;
-	size_t iov_len;
-	size_t size;
-};
-
 static inline struct obuf_svp
 obuf_create_svp(struct obuf *buf)
 {
diff --git a/src/iobuf.m b/src/iobuf.m
index d230a0f735587e1872bd3d9d0cd89823335cc83d..a54b722d7c1163ec8bc4c468da9b0ae8ca892eba 100644
--- a/src/iobuf.m
+++ b/src/iobuf.m
@@ -200,7 +200,7 @@ obuf_dup(struct obuf *buf, void *data, size_t size)
 }
 
 /** Book a few bytes in the output buffer. */
-void *
+struct obuf_svp
 obuf_book(struct obuf *buf, size_t size)
 {
 	struct iovec *iov = &buf->iov[buf->pos];
@@ -221,11 +221,13 @@ obuf_book(struct obuf *buf, size_t size)
 			obuf_alloc_pos(buf, buf->pos, size);
 		}
 	}
-	void *booking = iov->iov_base + iov->iov_len;
+	struct obuf_svp svp = {
+		.pos = buf->pos, .iov_len = iov->iov_len, .size = buf->size
+	};
 	iov->iov_len += size;
 	buf->size += size;
 	assert(iov->iov_len <= buf->capacity[buf->pos]);
-	return booking;
+	return svp;
 }
 
 /** Forget about data in the output buffer beyond the savepoint. */
diff --git a/src/iproto.m b/src/iproto.m
index d3fa59411c86380a65a71d3e38f4687a39447c85..4e859b29cbad7d1ea8a9c8af45293790659f2497 100644
--- a/src/iproto.m
+++ b/src/iproto.m
@@ -138,8 +138,7 @@ port_iproto_add_tuple(struct port *ptr, struct tuple *tuple, u32 flags)
 	struct port_iproto *port = port_iproto(ptr);
 	if (++port->reply.found == 1) {
 		/* Found the first tuple, add header. */
-		port->svp = obuf_create_svp(port->buf);
-		obuf_book(port->buf, sizeof(port->reply));
+		port->svp = obuf_book(port->buf, sizeof(port->reply));
 	}
 	if (flags & BOX_RETURN_TUPLE) {
 		obuf_dup(port->buf, &tuple->bsize, tuple_len(tuple));
@@ -635,7 +634,14 @@ iproto_session_output_iobuf(struct iproto_session *session)
 {
 	if (obuf_size(&session->iobuf[1]->out))
 		return session->iobuf[1];
-	if (obuf_size(&session->iobuf[0]->out))
+	/*
+	 * Don't try to write from a newer buffer if an older one
+	 * exists: in case of a partial write of a newer buffer,
+	 * the client may end up getting a salad of different
+	 * pieces of replies from both buffers.
+	 */
+	if (ibuf_size(&session->iobuf[1]->in) == 0 &&
+	    obuf_size(&session->iobuf[0]->out))
 		return session->iobuf[0];
 	return NULL;
 }