Skip to content

Missing execution stack and output for handled errors #3646

@armenzg

Description

@armenzg

When capturing errors, the Sentry stack traces only contain the frames from when an error happens. It does not contain any frames from the beginning of the execution.

This screenshot shows that only lines 25 and 17 are tracked (see [1] for full code; link to event). Lines 11 and 29 are missing:
Image

You can also notice that all breadcrumbs are missing [2].

You can check how I hacked a script [3] to give those extra missing frames by using traceback.extract_stack(); if you're curious.
link to event
Image

[1]

import os
import traceback

import sentry_sdk
from sentry_sdk import capture_exception

sentry_sdk.init(dsn=os.environ.get("SENTRY_DSN"))


def main():
    foo()  # line 11


def foo():
    try:
        print("Message before exception")
        bar()  # line 17
    except Exception:
        print("Message after capturing exception")
        traceback.print_exc()
        capture_exception()


def bar():
    raise Exception("This is a test exception")  # line 25


if __name__ == "__main__":
    main()  # line 29

[2] Output

Message before exception
Message after capturing exception
Traceback (most recent call last):
  File "/Users/armenzg/code/learning/scripts/foo.py", line 16, in foo
    bar()
  File "/Users/armenzg/code/learning/scripts/foo.py", line 23, in bar
    raise Exception("This is a test exception")
Exception: This is a test exception

[3]

import os
import sys
import traceback

import sentry_sdk
from sentry_sdk import capture_exception

# For Python 3.11+
if sys.version_info >= (3, 11):
    from builtins import ExceptionGroup
else:
    # For Python versions before 3.11
    from exceptiongroup import ExceptionGroup

sentry_sdk.init(dsn=os.environ.get("SENTRY_DSN"))


class CustomException(Exception):
    def __init__(self, message, tb_frames):
        super().__init__(message)
        self.tb_frames = tb_frames

    def __str__(self):
        frames = []
        for f in self.tb_frames[:-1]:
            # File "sentry_capture_exception.py", line 34, in foo
            line1 = f'  File "{f[0]}", line {f[1]}, in {f[2]}'
            line2 = f"    {f[3]}"
            frames.append("\n".join([line1, line2]))
        tb_str = "\n".join(frames)
        # Sample:
        # Exception: This is a test exception
        #   File "sentry_capture_exception.py", line 40, in foo
        #     bar()
        #   File "sentry_capture_exception.py", line 58, in bar
        #     raise Exception("This is a test exception")
        return f"{self.__class__.__name__}: foo\n{tb_str}"


def main():
    foo()


def foo():
    try:
        bar()
    except Exception as original_error:
        stack_trace = traceback.extract_stack()
        stack_exception = CustomException("An error occurred", stack_trace)

        # Create an ExceptionGroup with the original error and traceback exception
        exception_group = ExceptionGroup(
            "Error occurred in foo()", [original_error, stack_exception]
        )

        # Capture the ExceptionGroup
        capture_exception(exception_group)


def bar():
    raise Exception("This is a test exception")


if __name__ == "__main__":
    main()

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions