-
Notifications
You must be signed in to change notification settings - Fork 589
Description
How do you use Sentry?
Sentry Saas (sentry.io)
Version
1.21.1
Steps to Reproduce
- Setup a FastAPI app
- Configure Sentry with the StarletteIntegration and FastApiIntegration
- Create a custom exception class MyError with attribute status_code
- Create a FastAPI endpoint that raises MyError with status_code='N/A'
- Call the FastAPI endpoint
Expected Result
MyError caught by FastAPI error handler.
The error in my application is specific to the opensearchpy package available on pypi. The ConnectionTimeout class has a status_code that may be an int or a string. It is required to be "N/A" if no status code is available, which is the case for client side connection timeouts.
When this error bubbles its way up to the Sentry Starlette integration to be reported as an error, it finds the status_code field and checks to see if it is a 500 error. This comparison fails because there is no valid status code, instead, it ends up comparing "N/A" >= 500, thus leading to a TypeError.
I would suggest the Starlette integration be updated to verify the status_code is an instance of int before trying to compare it to one. This will handle cases where status code may be a string "N/A", None, or something else.
Actual Result
An unhandled TypeError is raised from the Sentry patched Starlette exception handler
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/starlette/testclient.py:590: in post
return super().post(
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/httpx/_client.py:1132: in post
return self.request(
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/starlette/testclient.py:465: in request
return super().request(
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/httpx/_client.py:814: in request
return self.send(request, auth=auth, follow_redirects=follow_redirects)
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/sentry_sdk/integrations/httpx.py:65: in send
rv = real_send(self, request, **kwargs)
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/httpx/_client.py:901: in send
response = self._send_handling_auth(
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/httpx/_client.py:929: in _send_handling_auth
response = self._send_handling_redirects(
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/httpx/_client.py:966: in _send_handling_redirects
response = self._send_single_request(request)
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/httpx/_client.py:1002: in _send_single_request
response = transport.handle_request(request)
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/starlette/testclient.py:342: in handle_request
raise exc
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/starlette/testclient.py:339: in handle_request
portal.call(self.app, scope, receive, send)
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/anyio/from_thread.py:283: in call
return cast(T_Retval, self.start_task_soon(func, *args).result())
/opt/local/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/concurrent/futures/_base.py:458: in result
return self.__get_result()
/opt/local/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/concurrent/futures/_base.py:403: in __get_result
raise self._exception
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/anyio/from_thread.py:219: in _call_func
retval = await retval
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/fastapi/applications.py:276: in __call__
await super().__call__(scope, receive, send)
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/sentry_sdk/integrations/starlette.py:333: in _sentry_patched_asgi_app
return await middleware(scope, receive, send)
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/sentry_sdk/integrations/asgi.py:139: in _run_asgi3
return await self._run_app(scope, lambda: self.app(scope, receive, send))
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/sentry_sdk/integrations/asgi.py:188: in _run_app
raise exc from None
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/sentry_sdk/integrations/asgi.py:183: in _run_app
return await callback()
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/starlette/applications.py:122: in __call__
await self.middleware_stack(scope, receive, send)
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/sentry_sdk/integrations/starlette.py:130: in _create_span_call
return await old_call(app, scope, new_receive, new_send, **kwargs)
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/starlette/middleware/errors.py:184: in __call__
raise exc
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/starlette/middleware/errors.py:162: in __call__
await self.app(scope, receive, _send)
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/sentry_sdk/integrations/asgi.py:139: in _run_asgi3
return await self._run_app(scope, lambda: self.app(scope, receive, send))
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/sentry_sdk/integrations/asgi.py:149: in _run_app
raise exc from None
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/sentry_sdk/integrations/asgi.py:146: in _run_app
return await callback()
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/starlette/middleware/cors.py:84: in __call__
await self.app(scope, receive, send)
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/starlette/middleware/gzip.py:24: in __call__
await responder(scope, receive, send)
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/starlette/middleware/gzip.py:44: in __call__
await self.app(scope, receive, self.send_with_gzip)
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/sentry_sdk/integrations/starlette.py:227: in _sentry_exceptionmiddleware_call
await old_call(self, scope, receive, send)
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/sentry_sdk/integrations/starlette.py:130: in _create_span_call
return await old_call(app, scope, new_receive, new_send, **kwargs)
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/starlette/middleware/exceptions.py:88: in __call__
response = await handler(request, exc)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <starlette.requests.Request object at 0x1070bd540>
args = (ConnectionTimeout('N/A', 'Timeout', 'Read timed out'),), kwargs = {}
exp = ConnectionTimeout('N/A', 'Timeout', 'Read timed out')
async def _sentry_patched_exception_handler(self, *args, **kwargs):
# type: (Any, Any, Any) -> None
exp = args[0]
is_http_server_error = (
> hasattr(exp, "status_code") and exp.status_code >= 500
)
E TypeError: '>=' not supported between instances of 'str' and 'int'
../../../../.virtualenvs/my_api-tckt/lib/python3.10/site-packages/sentry_sdk/integrations/starlette.py:186: TypeError