# Buggy code
def detach(self, session):
    """
    Implements :func:`crossbar.router.interfaces.IDealer.detach`
    """
    if session in self._session_to_registrations:
        # send out Errors for any in-flight calls we have
        outstanding = self._callee_to_invocations.get(session, [])
        for invoke in outstanding:
            self.log.debug(
                "Cancelling in-flight INVOKE with id={request} on session {session}",
                request=invoke.call.request,
                session=session._session_id,
            )
            reply = message.Error(
                message.Call.MESSAGE_TYPE,
                invoke.call.request,
                ApplicationError.CANCELED,
                ["callee disconnected from in-flight request"],
            )
            # send this directly to the caller's session
            invoke.caller._transport.send(reply)

        for registration in self._session_to_registrations[session]:
            was_registered, was_last_callee = self._registration_map.drop_observer(
                session, registration
            )

            if was_registered and was_last_callee:
                self._registration_map.delete_observation(registration)

            # publish WAMP meta events
            #
            if self._router._realm:
                service_session = self._router._realm.session
                if service_session and not registration.uri.startswith("wamp."):
                    if was_registered:
                        service_session.publish(
                            "wamp.registration.on_unregister",
                            session._session_id,
                            registration.id,
                        )
                    if was_last_callee:
                        service_session.publish(
                            "wamp.registration.on_delete",
                            session._session_id,
                            registration.id,
                        )

        del self._session_to_registrations[session]

    else:
        raise Exception("session with ID {} not attached".format(session._session_id))


# Traceback (PMbuiltins.AttributeError)
3/2/2017 8:26:29 PM2017-03-02T20:26:29+0000 [Router         13] Unhandled error in Deferred:
3/2/2017 8:26:29 PM2017-03-02T20:26:29+0000 [Router         13]
3/2/2017 8:26:29 PMTraceback (most recent call last):
3/2/2017 8:26:29 PM  File "/usr/local/lib/python3.6/site-packages/crossbar/router/router.py", line 192, in process
3/2/2017 8:26:29 PM    self._dealer.processCall(session, msg)
3/2/2017 8:26:29 PM  File "/usr/local/lib/python3.6/site-packages/crossbar/router/dealer.py", line 464, in processCall
3/2/2017 8:26:29 PM    txaio.add_callbacks(d, on_authorize_success, on_authorize_error)
3/2/2017 8:26:29 PM  File "/usr/local/lib/python3.6/site-packages/txaio/tx.py", line 490, in add_callbacks
3/2/2017 8:26:29 PM    future.addCallbacks(callback, errback)
3/2/2017 8:26:29 PM  File "/usr/local/lib/python3.6/site-packages/twisted/internet/defer.py", line 310, in addCallbacks
3/2/2017 8:26:29 PM    self._runCallbacks()
3/2/2017 8:26:29 PM--- <exception caught here> ---
3/2/2017 8:26:29 PM  File "/usr/local/lib/python3.6/site-packages/twisted/internet/defer.py", line 653, in _runCallbacks
3/2/2017 8:26:29 PM    current.result = callback(current.result, *args, **kw)
3/2/2017 8:26:29 PM  File "/usr/local/lib/python3.6/site-packages/crossbar/router/dealer.py", line 447, in on_authorize_success
3/2/2017 8:26:29 PM    self._call(session, call, registration, authorization)
3/2/2017 8:26:29 PM  File "/usr/local/lib/python3.6/site-packages/crossbar/router/dealer.py", line 627, in _call
3/2/2017 8:26:29 PM    self._router.send(callee, invocation)
3/2/2017 8:26:29 PM  File "/usr/local/lib/python3.6/site-packages/crossbar/router/router.py", line 163, in send
3/2/2017 8:26:29 PM    session._transport.send(msg)
3/2/2017 8:26:29 PMbuiltins.AttributeError: 'NoneType' object has no attribute 'send'

# Fixed code
def detach(self, session):
    """
    Implements :func:`crossbar.router.interfaces.IDealer.detach`
    """
    if session in self._session_to_registrations:
        # send out Errors for any in-flight calls we have
        outstanding = self._callee_to_invocations.get(session, [])
        for invoke in outstanding:
            self.log.debug(
                "Cancelling in-flight INVOKE with id={request} on session {session}",
                request=invoke.call.request,
                session=session._session_id,
            )
            reply = message.Error(
                message.Call.MESSAGE_TYPE,
                invoke.call.request,
                ApplicationError.CANCELED,
                ["callee disconnected from in-flight request"],
            )
            # send this directly to the caller's session
            # (it is possible the caller was disconnected and thus
            # _transport is None before we get here though)
            if invoke.caller._transport:
                invoke.caller._transport.send(reply)

        for registration in self._session_to_registrations[session]:
            was_registered, was_last_callee = self._registration_map.drop_observer(
                session, registration
            )

            if was_registered and was_last_callee:
                self._registration_map.delete_observation(registration)

            # publish WAMP meta events
            #
            if self._router._realm:
                service_session = self._router._realm.session
                if service_session and not registration.uri.startswith("wamp."):
                    if was_registered:
                        service_session.publish(
                            "wamp.registration.on_unregister",
                            session._session_id,
                            registration.id,
                        )
                    if was_last_callee:
                        service_session.publish(
                            "wamp.registration.on_delete",
                            session._session_id,
                            registration.id,
                        )

        del self._session_to_registrations[session]

    else:
        raise Exception("session with ID {} not attached".format(session._session_id))