Browse Source

feat: display exact error for runtime requests exception handling (#5386)

Xingyao Wang 1 year ago
parent
commit
d0b5dd3000
2 changed files with 26 additions and 52 deletions
  1. 8 8
      openhands/runtime/action_execution_server.py
  2. 18 44
      openhands/runtime/utils/request.py

+ 8 - 8
openhands/runtime/action_execution_server.py

@@ -14,6 +14,7 @@ import os
 import shutil
 import tempfile
 import time
+import traceback
 from contextlib import asynccontextmanager
 from pathlib import Path
 from zipfile import ZipFile
@@ -383,17 +384,13 @@ if __name__ == '__main__':
         logger.exception('Unhandled exception occurred:')
         return JSONResponse(
             status_code=500,
-            content={
-                'message': 'An unexpected error occurred. Please try again later.'
-            },
+            content={'detail': 'An unexpected error occurred. Please try again later.'},
         )
 
     @app.exception_handler(StarletteHTTPException)
     async def http_exception_handler(request: Request, exc: StarletteHTTPException):
         logger.error(f'HTTP exception occurred: {exc.detail}')
-        return JSONResponse(
-            status_code=exc.status_code, content={'message': exc.detail}
-        )
+        return JSONResponse(status_code=exc.status_code, content={'detail': exc.detail})
 
     @app.exception_handler(RequestValidationError)
     async def validation_exception_handler(
@@ -402,7 +399,7 @@ if __name__ == '__main__':
         logger.error(f'Validation error occurred: {exc}')
         return JSONResponse(
             status_code=422,
-            content={'message': 'Invalid request parameters', 'details': exc.errors()},
+            content={'detail': 'Invalid request parameters', 'errors': exc.errors()},
         )
 
     @app.middleware('http')
@@ -444,7 +441,10 @@ if __name__ == '__main__':
             logger.error(
                 f'Error processing command: {str(e)}', exc_info=True, stack_info=True
             )
-            raise HTTPException(status_code=500, detail=str(e))
+            raise HTTPException(
+                status_code=500,
+                detail=traceback.format_exc(),
+            )
 
     @app.post('/upload_file')
     async def upload_file(

+ 18 - 44
openhands/runtime/utils/request.py

@@ -1,53 +1,20 @@
 from typing import Any
 
 import requests
-from requests.exceptions import (
-    ChunkedEncodingError,
-    ConnectionError,
-)
-from urllib3.exceptions import IncompleteRead
 
 
-def is_server_error(exception):
-    return (
-        isinstance(exception, requests.HTTPError)
-        and exception.response.status_code >= 500
-    )
+class RequestHTTPError(requests.HTTPError):
+    """Exception raised when an error occurs in a request with details."""
 
+    def __init__(self, *args, detail=None, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.detail = detail
 
-def is_404_error(exception):
-    return (
-        isinstance(exception, requests.HTTPError)
-        and exception.response.status_code == 404
-    )
-
-
-def is_429_error(exception):
-    return (
-        isinstance(exception, requests.HTTPError)
-        and exception.response.status_code == 429
-    )
-
-
-def is_503_error(exception):
-    return (
-        isinstance(exception, requests.HTTPError)
-        and exception.response.status_code == 503
-    )
-
-
-def is_502_error(exception):
-    return (
-        isinstance(exception, requests.HTTPError)
-        and exception.response.status_code == 502
-    )
-
-
-DEFAULT_RETRY_EXCEPTIONS = [
-    ConnectionError,
-    IncompleteRead,
-    ChunkedEncodingError,
-]
+    def __str__(self) -> str:
+        s = super().__str__()
+        if self.detail is not None:
+            s += f'\nDetails: {self.detail}'
+        return s
 
 
 def send_request(
@@ -58,5 +25,12 @@ def send_request(
     **kwargs: Any,
 ) -> requests.Response:
     response = session.request(method, url, **kwargs)
-    response.raise_for_status()
+    try:
+        response.raise_for_status()
+    except requests.HTTPError as e:
+        try:
+            _json = response.json()
+        except requests.JSONDecodeError:
+            raise e
+        raise RequestHTTPError(e, detail=_json.get('detail')) from e
     return response