Opened 2 months ago

Last modified 2 months ago

#31672 new Cleanup/optimization

debug error view shows no traceback if exc.__traceback__ is None for innermost exception

Reported by: Chris Jerdonek Owned by:
Component: Error reporting Version: master
Severity: Normal Keywords: technical_500_response, traceback, chain
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Consider this test view which raises an exception:

class TestView(View):

    def get(self, request, *args, **kwargs):
        try:
            raise RuntimeError('my error')
        except Exception as exc:
            # Uncommenting these two lines causes the debug
            # server error view not to show **any** portion
            # of the traceback.
            # new_exc = RuntimeError('my context')
            # exc.__context__ = new_exc

            raise

If the indicated lines are uncommented, then the debug error view shows no traceback info at all.

This is because django.views.debug.get_traceback_frames() starts at the innermost exception in the chain, and then stops adding frames when it encounters the first exception with None-valued exc_value.__traceback__:
https://github.com/django/django/blob/38a21f2d9ed4f556af934498ec6a242f6a20418a/django/views/debug.py#L391

exc_value = exceptions.pop()
tb = self.tb if not exceptions else exc_value.__traceback__

while tb is not None:
    # Get frame.
    ...
    frames.append({
        ...
    })

    # If the traceback for current exception is consumed, try the
    # other exception.
    if not tb.tb_next and exceptions:
        exc_value = exceptions.pop()
        tb = exc_value.__traceback__
    else:
        tb = tb.tb_next

return frames

It would probably be better and simpler if instead the while loop were structured to iterate over every exception in the chain no matter what, and include traceback info only for those exceptions with non-None __traceback__. In other words, something like the following:

while exceptions:
    exc_value = exceptions.pop()
    # Returns placeholder frame with no `tb` info if
    # `exc_value.__traceback__ is None`.
    exc_frames = self.get_traceback_frames(exc_value)
    frames.extend(exc_frames)

This way, the debug error view would always show the complete exception chain, even if some exceptions in the chain have a None-valued traceback attribute.

Change History (3)

comment:1 Changed 2 months ago by Chris Jerdonek

Here is a related (but different) issue about the traceback shown by the debug error view ("debug error view doesn't respect exc.__suppress_context__ (PEP 415)"): https://code.djangoproject.com/ticket/31674

Last edited 2 months ago by Chris Jerdonek (previous) (diff)

comment:2 Changed 2 months ago by felixxm

Triage Stage: UnreviewedAccepted
Type: UncategorizedCleanup/optimization
Version: 3.0master

Thanks for the report. Would you like to prepare a patch?

comment:3 Changed 2 months ago by Chris Jerdonek

Sure, I'll see if I can find time to put something together for this and the others.

By the way, have there been any issues with people not receiving all email notifications from code.djangoproject.com? It seems like I don't get some of them (not even to my spam folder).

Note: See TracTickets for help on using tickets.
Back to Top