getsentry / getsentry/sentry-python

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

Abierto
#5,050 4 comentarios 1 reacción 1 asignado Reclamado por @alexander-alderman-webb Ver en GitHub
Bug Errors Python
Lenguaje dominante
Python
Estrellas
2.2k
Forks
669
Merge medio
1 d 1 h
PR fusionados (30 d)
213

Descripción

### 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'
```

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.