Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

avoid twisted's overly eager traceback trimming

So this is a subtle one. Twisted's error handling is pretty hugely
complex, in the interest of re-creating tracebacks to be more
reminiscent of the async execution flow. Thrift is creating exceptions
and errbacking Deferreds with them (instead of raising the exceptions),
which means it has no meaningful traceback to attach to the Failure
objects created. Twisted wants to keep only the traceback attached to a
Failure in the first place (the lowest part), plus the traceback that
was caught the last time the Failure was raised (the highest part).  The
detection of 'the middle part' is made by inspecting the deepest part of
a traceback: if an error being errbacked was originated by
Failure.raiseException(), or Failure.throwExceptionIntoGenerator(), then
the original Failure object is plucked out and any intervening traceback
is discarded.

In the case of Thrift-twisted code below an inlineCallbacks-wrapped
generator, the 'highest part' of the traceback is empty, and the 'lowest
part' is also empty when coming from throwExceptionIntoGenerator(), so
Thrift tracebacks are free of useful context.

This fix creates a new Failure object within Telephus when we receive a
traceback-less Failure from Thrift. The new Failure is equivalent to the
old, except it is not originated in one of the Failure.reraise methods,
which makes more traceback get collected once we are above it on the

Phew, mucking with Twisted error handling always makes me want to go
straight to Erlang and never look back.
  • Loading branch information...
commit cb812ec6f647d0a7e25ee9fe2647dc92c9634753 1 parent 01171f3
@thepaul thepaul authored
Showing with 11 additions and 0 deletions.
  1. +11 −0 telephus/
11 telephus/
@@ -3,8 +3,10 @@
from twisted.internet.protocol import ReconnectingClientFactory
from twisted.internet import defer, reactor
from twisted.internet.error import UserError
+from twisted.python import failure
from telephus.cassandra import Cassandra, constants
from telephus.cassandra.ttypes import *
+from sys import exc_info
class ClientBusy(Exception):
@@ -194,6 +196,15 @@ def submitRequest(self, proto):
def reqError(err, req, d, r):
if isinstance(err, InvalidRequestException) or \
isinstance(err, InvalidThriftRequest) or r < 1:
+ if err.tb is None:
+ try:
+ raise err.value
+ except Exception:
+ # make new Failure object explicitly, so that the same
+ # (traceback-less) one made by Thrift won't be retained
+ # and useful tracebacks thrown away
+ t, v, tb = exc_info()
+ err = failure.Failure(v, t, tb)
Please sign in to comment.
Something went wrong with that request. Please try again.