diff --git a/src/box/applier.cc b/src/box/applier.cc
index 0f214d965a632c54e393c4ea5608ddf6b8d7f4e0..47304820b684489add4bc5832791a8048ea85ee9 100644
--- a/src/box/applier.cc
+++ b/src/box/applier.cc
@@ -350,7 +350,8 @@ applier_connect(struct applier *applier)
 	if (fd < 0)
 		diag_raise();
 	iostream_create(io, fd);
-	coio_readn(io, greetingbuf, IPROTO_GREETING_SIZE);
+	if (coio_readn(io, greetingbuf, IPROTO_GREETING_SIZE) < 0)
+		diag_raise();
 	applier->last_row_time = ev_monotonic_now(loop());
 
 	/* Decode instance version and name from greeting */
diff --git a/src/box/lua/console.c b/src/box/lua/console.c
index bcda392572e5d7804f3def4c41e128acc67b4445..eacf086446507f44425acfa1ae946e39948cafcb 100644
--- a/src/box/lua/console.c
+++ b/src/box/lua/console.c
@@ -576,8 +576,7 @@ console_session_push(struct session *session, struct port *port)
 		return -1;
 	struct iostream io;
 	iostream_create(&io, session_fd(session));
-	int ret = coio_write_timeout_noxc(&io, text, text_len,
-					  TIMEOUT_INFINITY);
+	int ret = coio_write_timeout(&io, text, text_len, TIMEOUT_INFINITY);
 	iostream_destroy(&io);
 	return ret >= 0 ? 0 : -1;
 }
diff --git a/src/box/xrow_io.cc b/src/box/xrow_io.cc
index bfe335c9dc595695b01e495ca41c3ddc517f12bb..20e32723943e49868966d87e95fb22d572b5e7d0 100644
--- a/src/box/xrow_io.cc
+++ b/src/box/xrow_io.cc
@@ -100,6 +100,7 @@ coio_write_xrow(struct iostream *io, const struct xrow_header *row)
 {
 	struct iovec iov[XROW_IOVMAX];
 	int iovcnt = xrow_to_iovec_xc(row, iov);
-	coio_writev(io, iov, iovcnt, 0);
+	if (coio_writev(io, iov, iovcnt, 0) < 0)
+		diag_raise();
 }
 
diff --git a/src/lib/core/coio.cc b/src/lib/core/coio.cc
index c5f41c17fb41feb03ffb59bce589576724a7d5a6..3fde60e8667e8fced53ee62225f60bcfa434039a 100644
--- a/src/lib/core/coio.cc
+++ b/src/lib/core/coio.cc
@@ -258,6 +258,7 @@ coio_accept(int sfd, struct sockaddr *addr, socklen_t addrlen,
  * Can read up to bufsiz bytes.
  *
  * @retval the number of bytes read.
+ * @retval -1 error.
  */
 ssize_t
 coio_read_ahead_timeout(struct iostream *io, void *buf, size_t sz,
@@ -284,7 +285,7 @@ coio_read_ahead_timeout(struct iostream *io, void *buf, size_t sz,
 		} else if (nrd == 0) {
 			return sz - to_read;
 		} else if (nrd == IOSTREAM_ERROR) {
-			diag_raise();
+			return -1;
 		}
 		/*
 		 * Yield control to other fibers until the
@@ -292,9 +293,14 @@ coio_read_ahead_timeout(struct iostream *io, void *buf, size_t sz,
 		 */
 		int revents = coio_wait(io->fd, iostream_status_to_events(nrd),
 					delay);
-		fiber_testcancel();
-		if (revents == 0)
-			tnt_raise(TimedOut);
+		if (fiber_is_cancelled()) {
+			diag_set(FiberIsCancelled);
+			return -1;
+		}
+		if (revents == 0) {
+			diag_set(TimedOut);
+			return -1;
+		}
 		coio_timeout_update(&start, &delay);
 	}
 }
@@ -305,15 +311,17 @@ coio_read_ahead_timeout(struct iostream *io, void *buf, size_t sz,
  * Treats EOF as an error, and throws an exception.
  *
  * @retval the number of bytes read, > 0.
+ * @retval -1 error.
  */
 ssize_t
 coio_readn_ahead(struct iostream *io, void *buf, size_t sz, size_t bufsiz)
 {
 	ssize_t nrd = coio_read_ahead(io, buf, sz, bufsiz);
-	if (nrd < (ssize_t)sz) {
+	if (nrd >= 0 && nrd < (ssize_t)sz) {
 		errno = EPIPE;
-		tnt_raise(SocketError, sio_socketname(io->fd),
-			  "unexpected EOF when reading from socket");
+		diag_set(SocketError, sio_socketname(io->fd),
+			 "unexpected EOF when reading from socket");
+		return -1;
 	}
 	return nrd;
 }
@@ -324,6 +332,7 @@ coio_readn_ahead(struct iostream *io, void *buf, size_t sz, size_t bufsiz)
  * Treats EOF as an error, and throws an exception.
  *
  * @retval the number of bytes read, > 0.
+ * @retval -1 error.
  */
 ssize_t
 coio_readn_ahead_timeout(struct iostream *io, void *buf, size_t sz,
@@ -332,32 +341,13 @@ coio_readn_ahead_timeout(struct iostream *io, void *buf, size_t sz,
 	ssize_t nrd = coio_read_ahead_timeout(io, buf, sz, bufsiz, timeout);
 	if (nrd >= 0 && nrd < (ssize_t)sz) { /* EOF. */
 		errno = EPIPE;
-		tnt_raise(SocketError, sio_socketname(io->fd),
-			  "unexpected EOF when reading from socket");
+		diag_set(SocketError, sio_socketname(io->fd),
+			 "unexpected EOF when reading from socket");
+		return -1;
 	}
 	return nrd;
 }
 
-/*
- * FIXME: Rewrite coio_read_ahead_timeout() w/o C++ exceptions and
- * drop this function.
- */
-ssize_t
-coio_read_ahead_timeout_noxc(struct iostream *io, void *buf, size_t sz,
-			     size_t bufsiz, ev_tstamp timeout)
-{
-	try {
-		return coio_read_ahead_timeout(io, buf, sz, bufsiz, timeout);
-	} catch (Exception *) {
-		/*
-		 * The exception is already in the diagnostics
-		 * area. Nothing to do.
-		 */
-	}
-	return -1;
-}
-
-
 /**
  * Write sz bytes to socket.
  *
@@ -368,6 +358,7 @@ coio_read_ahead_timeout_noxc(struct iostream *io, void *buf, size_t sz,
  *
  * @retval the number of bytes written. Always
  * equal to @a sz.
+ * @retval -1 error.
  */
 ssize_t
 coio_write_timeout(struct iostream *io, const void *buf, size_t sz,
@@ -390,7 +381,7 @@ coio_write_timeout(struct iostream *io, const void *buf, size_t sz,
 			buf = (char *) buf + nwr;
 			continue;
 		} else if (nwr == IOSTREAM_ERROR) {
-			diag_raise();
+			return -1;
 		}
 		/*
 		 * Yield control to other fibers until the
@@ -399,32 +390,18 @@ coio_write_timeout(struct iostream *io, const void *buf, size_t sz,
 		 */
 		int revents = coio_wait(io->fd, iostream_status_to_events(nwr),
 					delay);
-		fiber_testcancel();
-		if (revents == 0)
-			tnt_raise(TimedOut);
+		if (fiber_is_cancelled()) {
+			diag_set(FiberIsCancelled);
+			return -1;
+		}
+		if (revents == 0) {
+			diag_set(TimedOut);
+			return -1;
+		}
 		coio_timeout_update(&start, &delay);
 	}
 }
 
-/*
- * FIXME: Rewrite coio_write_timeout() w/o C++ exceptions and drop
- * this function.
- */
-ssize_t
-coio_write_timeout_noxc(struct iostream *io, const void *buf, size_t sz,
-			ev_tstamp timeout)
-{
-	try {
-		return coio_write_timeout(io, buf, sz, timeout);
-	} catch (Exception *) {
-		/*
-		 * The exception is already in the diagnostics
-		 * area. Nothing to do.
-		 */
-	}
-	return -1;
-}
-
 /*
  * Write iov using iostream API.
  * Put in an own function to workaround gcc bug with @finally
@@ -468,7 +445,7 @@ coio_writev_timeout(struct iostream *io, struct iovec *iov, int iovcnt,
 			}
 			continue;
 		} else if (nwr == IOSTREAM_ERROR) {
-			diag_raise();
+			return -1;
 		}
 		/*
 		 * Yield control to other fibers until the
@@ -477,9 +454,14 @@ coio_writev_timeout(struct iostream *io, struct iovec *iov, int iovcnt,
 		 */
 		int revents = coio_wait(io->fd, iostream_status_to_events(nwr),
 					delay);
-		fiber_testcancel();
-		if (revents == 0)
-			tnt_raise(TimedOut);
+		if (fiber_is_cancelled()) {
+			diag_set(FiberIsCancelled);
+			return -1;
+		}
+		if (revents == 0) {
+			diag_set(TimedOut);
+			return -1;
+		}
 		coio_timeout_update(&start, &delay);
 	}
 	return total;
diff --git a/src/lib/core/coio.h b/src/lib/core/coio.h
index 3a54289b39e132f93733d999bd094ae57b2b5ebf..84b741603bf00178a5ea3a0ac918fafbba16096d 100644
--- a/src/lib/core/coio.h
+++ b/src/lib/core/coio.h
@@ -92,7 +92,7 @@ coio_timeout_update(ev_tstamp *start, ev_tstamp *delay)
 /**
  * Reat at least sz bytes, with readahead.
  *
- * Returns 0 in case of EOF.
+ * Returns 0 in case of EOF, -1 in case of error.
  */
 static inline ssize_t
 coio_read_ahead(struct iostream *io, void *buf, size_t sz, size_t bufsiz)
@@ -115,29 +115,6 @@ coio_read_timeout(struct iostream *io, void *buf, size_t sz, ev_tstamp timeout)
 	return coio_read_ahead_timeout(io, buf, sz, sz, timeout);
 }
 
-/**
- * Read data with timeout.
- *
- * Yield until some data will be available for read.
- *
- * Returns amount of read bytes at success, otherwise returns -1
- * and set a diag.
- *
- * Zero return value means EOF.
- *
- * Note: Less then @a count bytes may be available for read at a
- * moment, so a return value less then @a count does not mean EOF.
- *
- * Possible errors:
- *
- * - SocketError: an IO error occurs at read().
- * - TimedOut: @a timeout quota is exceeded.
- * - FiberIsCancelled: cancelled by an outside code.
- */
-ssize_t
-coio_read_ahead_timeout_noxc(struct iostream *io, void *buf, size_t sz,
-			     size_t bufsiz, ev_tstamp timeout);
-
 static inline ssize_t
 coio_readn(struct iostream *io, void *buf, size_t sz)
 {
@@ -152,24 +129,6 @@ ssize_t
 coio_write_timeout(struct iostream *io, const void *buf, size_t sz,
 		   ev_tstamp timeout);
 
-/**
- * Write @a count bytes with timeout.
- *
- * Yield until all @a count bytes will be written.
- *
- * Returns @a count at success, otherwise returns -1 and set a
- * diag.
- *
- * Possible errors:
- *
- * - SocketError: an IO error occurs at write().
- * - TimedOut: @a timeout quota is exceeded.
- * - FiberIsCancelled: cancelled by an outside code.
- */
-ssize_t
-coio_write_timeout_noxc(struct iostream *io, const void *buf, size_t sz,
-			ev_tstamp timeout);
-
 static inline void
 coio_write(struct iostream *io, const void *buf, size_t sz)
 {
diff --git a/src/lib/core/coio_buf.h b/src/lib/core/coio_buf.h
index 4a840c974e0e0dbe8a120cbb490f54601f98330b..fabe54cfc0725c75d7d42f121c69e42996502596 100644
--- a/src/lib/core/coio_buf.h
+++ b/src/lib/core/coio_buf.h
@@ -31,6 +31,7 @@
  * SUCH DAMAGE.
  */
 #include "coio.h"
+#include "diag.h"
 #include <small/ibuf.h>
 
 struct iostream;
@@ -47,6 +48,8 @@ coio_bread(struct iostream *io, struct ibuf *buf, size_t sz)
 {
 	ibuf_reserve_xc(buf, sz);
 	ssize_t n = coio_read_ahead(io, buf->wpos, sz, ibuf_unused(buf));
+	if (n < 0)
+		diag_raise();
 	buf->wpos += n;
 	return n;
 }
@@ -63,6 +66,8 @@ coio_bread_timeout(struct iostream *io, struct ibuf *buf, size_t sz,
 	ibuf_reserve_xc(buf, sz);
 	ssize_t n = coio_read_ahead_timeout(io, buf->wpos, sz, ibuf_unused(buf),
 			                    timeout);
+	if (n < 0)
+		diag_raise();
 	buf->wpos += n;
 	return n;
 }
@@ -73,6 +78,8 @@ coio_breadn(struct iostream *io, struct ibuf *buf, size_t sz)
 {
 	ibuf_reserve_xc(buf, sz);
 	ssize_t n = coio_readn_ahead(io, buf->wpos, sz, ibuf_unused(buf));
+	if (n < 0)
+		diag_raise();
 	buf->wpos += n;
 	return n;
 }
@@ -90,6 +97,8 @@ coio_breadn_timeout(struct iostream *io, struct ibuf *buf, size_t sz,
 	ibuf_reserve_xc(buf, sz);
 	ssize_t n = coio_readn_ahead_timeout(io, buf->wpos, sz, ibuf_unused(buf),
 			                     timeout);
+	if (n < 0)
+		diag_raise();
 	buf->wpos += n;
 	return n;
 }
diff --git a/src/lib/core/popen.c b/src/lib/core/popen.c
index 73609b60fc69738aaf73057358600489518eb918..baf65b7ee64185b1298d9ded514d78cb7e1a9451 100644
--- a/src/lib/core/popen.c
+++ b/src/lib/core/popen.c
@@ -395,8 +395,7 @@ popen_write_timeout(struct popen_handle *handle, const void *buf,
 		  handle->pid, stdX_str(idx), idx, buf, count,
 		  handle->ios[idx].fd, timeout);
 
-	ssize_t rc = coio_write_timeout_noxc(&handle->ios[idx], buf,
-					     count, timeout);
+	ssize_t rc = coio_write_timeout(&handle->ios[idx], buf, count, timeout);
 	assert(rc < 0 || rc == (ssize_t)count);
 	return rc;
 }
@@ -460,8 +459,8 @@ popen_read_timeout(struct popen_handle *handle, void *buf,
 		  handle->pid, stdX_str(idx), idx, buf, count,
 		  handle->ios[idx].fd, timeout);
 
-	return coio_read_ahead_timeout_noxc(&handle->ios[idx], buf, 1, count,
-					    timeout);
+	return coio_read_ahead_timeout(&handle->ios[idx], buf, 1, count,
+				       timeout);
 }
 
 /**