diff --git a/src/common/eio.c b/src/common/eio.c
index dce5443d2edcdea303b116413ddf16688b3d02d3..22c587a0104a72766daa0c9eed0ced17d04022e2 100644
--- a/src/common/eio.c
+++ b/src/common/eio.c
@@ -290,13 +290,7 @@ _poll_handle_event(short revents, eio_obj_t *obj, List objList)
 	bool read_called = false;
 	bool write_called = false;
 
-	if (revents & POLLNVAL) {
-		debug("POLLNVAL on fd %d, shutting down eio object", obj->fd);
-		obj->shutdown = true;
-		return;
-	}
-
-	if (revents & POLLERR) {
+	if (revents & POLLERR || revents & POLLNVAL) {
 		if (obj->ops->handle_error) {
 			(*obj->ops->handle_error) (obj, objList);
 		} else if (obj->ops->handle_read) {
@@ -306,7 +300,9 @@ _poll_handle_event(short revents, eio_obj_t *obj, List objList)
 			(*obj->ops->handle_write) (obj, objList);
 			write_called = true;
 		} else {
-			debug("No handler for POLLERR");
+			debug("No handler for %s on fd %d",
+			      revents & POLLERR ? "POLLERR" : "POLLNVAL",
+			      obj->fd);
 			obj->shutdown = true;
 		}
 		return;
diff --git a/src/common/eio.h b/src/common/eio.h
index 95f31acf4d74b250e7692ea0832fee042f171ebd..83e660675dd35463d5bec741c7d25ab63cb831ef 100644
--- a/src/common/eio.h
+++ b/src/common/eio.h
@@ -39,6 +39,16 @@ typedef struct eio_handle_components eio_handle_t;
  *
  * handle_*() functions also pass the List of io_obj's from the event loop
  *
+ * If either "handle_error" (for POLLERR and POLLNVAL) or "handle_close"
+ * (for POLLHUP) are not defined, the eio server will fallback to handle_read
+ * if defined, and fallback to handle_write if handle_read is not defined
+ * either.
+ *
+ * If there are no handlers at all when POLLERR or POLLNVAL occurs, the eio
+ * server will set the eio_obj_t shutdown flag to "true".  Keep in mind
+ * that the shutdown flag is essentially just an advisory flag.  The
+ * "readable" and "writable" functions have the final say over whether a
+ * file descriptor will continue to be polled.
  */
 struct io_operations {
 	bool (*readable    )(eio_obj_t *);