# Buggy code
def on_message(self, fragment):
    """Process an individual wire protocol fragment.

        The websocket RFC specifies opcodes for distinguishing
        text frames from binary frames. Tornado passes us either
        a text or binary string depending on that opcode, we have
        to look at the type of the fragment to see what we got.

    Args:
        fragment (unicode or bytes) : wire fragment to process

    """

    # We shouldn't throw exceptions from on_message because
    # the caller is just Tornado and it doesn't know what to
    # do with them other than report them as an unhandled
    # Future

    try:
        message = yield self._receive(fragment)
    except Exception as e:
        # If you go look at self._receive, it's catching the
        # expected error types... here we have something weird.
        log.error(
            "Unhandled exception receiving a message: %r: %r",
            e,
            fragment,
            exc_info=True,
        )
        self._internal_error("server failed to parse a message")

    try:
        if message:
            work = yield self._handle(message)
            if work:
                yield self._schedule(work)
    except Exception as e:
        log.error(
            "Handler or its work threw an exception: %r: %r", e, message, exc_info=True
        )
        self._internal_error("server failed to handle a message")

    raise gen.Return(None)


# Traceback (tornado.iostream.StreamClosedError)
2018-03-12 09:05:56,504 200 GET /gapminder (::1) 134.13ms
2018-03-12 09:05:56,506 Sending pull-doc-reply from session 'c13X3Xet3szgUeNWFMzrL86pmFq77b8q04pGAUD8WUFJ'
2018-03-12 09:05:56,513 Failed sending message as connection was closed
2018-03-12 09:05:56,514 WebSocket connection closed: code=None, reason=None
2018-03-12 09:05:56,604 Future exception was never retrieved
future: <Future finished exception=WebSocketClosedError()>
Traceback (most recent call last):
File "/Users/bryanv/anaconda/envs/15dev1/lib/python3.6/site-packages/tornado/websocket.py", line 808, in wrapper
yield fut
File "/Users/bryanv/anaconda/envs/15dev1/lib/python3.6/site-packages/tornado/gen.py", line 1099, in run
value = future.result()
tornado.iostream.StreamClosedError: Stream is closed

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/Users/bryanv/anaconda/envs/15dev1/lib/python3.6/site-packages/tornado/gen.py", line 1107, in run
yielded = self.gen.throw(*exc_info)
File "/Users/bryanv/anaconda/envs/15dev1/lib/python3.6/site-packages/tornado/websocket.py", line 810, in wrapper
raise WebSocketClosedError()
tornado.websocket.WebSocketClosedError

# Fixed code
def on_message(self, fragment):
    """Process an individual wire protocol fragment.

    The websocket RFC specifies opcodes for distinguishing text frames
    from binary frames. Tornado passes us either a text or binary string
    depending on that opcode, we have to look at the type of the fragment
    to see what we got.

    Args:
        fragment (unicode or bytes) : wire fragment to process

    """

    # We shouldn't throw exceptions from on_message because the caller is
    # just Tornado and it doesn't know what to do with them other than
    # report them as an unhandled Future

    try:
        message = yield self._receive(fragment)
    except Exception as e:
        # If you go look at self._receive, it's catching the
        # expected error types... here we have something weird.
        log.error(
            "Unhandled exception receiving a message: %r: %r",
            e,
            fragment,
            exc_info=True,
        )
        self._internal_error("server failed to parse a message")

    try:
        if message:
            work = yield self._handle(message)
            if work:
                yield self._schedule(work)
    except Exception as e:
        log.error(
            "Handler or its work threw an exception: %r: %r", e, message, exc_info=True
        )
        self._internal_error("server failed to handle a message")

    raise gen.Return(None)