getsentry / getsentry/sentry-python

Exceptions are formatted incorrectly (or even fail) when `message` or `detail` attribute presents

Ouverte
#5,050 4 commentaires 1 réaction 1 personne assignée Réclamée par @alexander-alderman-webb Voir sur GitHub
Bug Errors Python
Langage dominant
Python
Étoiles
2.2k
Forks
669
Merge moyen
1 j 1 h
PR mergées (30 j)
213

Description

### How do you use Sentry?

Self-hosted/on-premise

### Version

2.43.0

### Steps to Reproduce

Some of our exception define properties `message` and `detail`. The formatting of error message for those exceptions is almost always incorrect (doesn't contain important information, not formatted properly) or sometimes even fails. There is a couple of such exceptions in simplified form:

```python
class GRpcError(Exception):
def __init__(self, code: int, message: bytes) -> None:
super().__init__(code, message)
self.code = code
# Original protobuf message to allow its inspection in error handlers.
# Here we use bytes, but it can be `google.protobuf.message.Message`
# instance as well.
self.message = message

def __str__(self) -> str:
return f"code={self.code}"

class ApiError(Exception):
def __init__(self, code: str, detail: dict[str, Any]) -> None:
super().__init__(code, detail)
self.code = code
self.detail = detail

def __str__(self) -> str:
formatted = f"[{self.code}]"
for key, value in self.detail.items():
formatted += f"\n {key}={value}"
return formatted
```

### Expected Result

Here is how they are formatted by Python itself:
```python
grpc_exc = GRpcError(13, b"unreadable protobuf message")

print("".join(traceback.format_exception_only(grpc_exc)).strip())
# GRpcError: code=13

grpc_exc.add_note("additional context note")

print("".join(traceback.format_exception_only(grpc_exc)).strip())
# GRpcError: code=13
# additional context note

api_exc = ApiError("RATE_LIMIT_EXCEEDED", detail={"retry_after": 30})

print("".join(traceback.format_exception_only(api_exc)).strip())
# ApiError: [RATE_LIMIT_EXCEEDED]
# retry_after=30

api_exc.add_note("additional context note")

print("".join(traceback.format_exception_only(api_exc)).strip())
# ApiError: [RATE_LIMIT_EXCEEDED]
# retry_after=30
# additional context note
```

### Actual Result

And the formatting by sentry (`get_error_message` is used internally by `event_from_exception`, here I call it directly):

```python
grpc_exc = GRpcError(13, b"unreadable protobuf message")

print(sentry_sdk.utils.get_error_message(grpc_exc))
# No `code` field, only unreadable field in the result:
# b'unreadable protobuf message'

grpc_exc.add_note("additional context note")

print(sentry_sdk.utils.get_error_message(grpc_exc))
# Fails with the error:
# TypeError: can't concat str to bytes

api_exc = ApiError("RATE_LIMIT_EXCEEDED", detail={"retry_after": 30})

print(sentry_sdk.utils.get_error_message(api_exc))
# No `code` field, `detail` is not formatted:
# {'retry_after': 30}

api_exc.add_note("additional context note")

print(sentry_sdk.utils.get_error_message(api_exc))
# Fails with the error:
# TypeError: unsupported operand type(s) for +=: 'dict' and 'str'
```

Guide de contribution

Ouvrir le guide de contribution

Évaluation

Cette issue n'a pas encore été évaluée.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.