diff --git a/supervisor/addons/addon.py b/supervisor/addons/addon.py index b49cc10f5..3734e4e93 100644 --- a/supervisor/addons/addon.py +++ b/supervisor/addons/addon.py @@ -567,7 +567,7 @@ class Addon(AddonModel): raise AddonsError() from err except DockerError as err: self.state = AddonState.ERROR - raise AddonsError(err) from err + raise AddonsError() from err else: self.state = AddonState.STARTED diff --git a/supervisor/api/utils.py b/supervisor/api/utils.py index 9c5fceefd..e9eeedc0d 100644 --- a/supervisor/api/utils.py +++ b/supervisor/api/utils.py @@ -17,7 +17,8 @@ from ..const import ( RESULT_ERROR, RESULT_OK, ) -from ..exceptions import APIError, APIForbidden, HassioError +from ..exceptions import APIError, APIForbidden, DockerAPIError, HassioError +from ..utils import check_exception_chain, get_message_from_exception_chain from ..utils.log_format import format_message @@ -57,12 +58,8 @@ def api_process(method): """Return API information.""" try: answer = await method(api, *args, **kwargs) - except (APIError, APIForbidden) as err: - return api_return_error(message=str(err)) - except HassioError as err: - return api_return_error( - message=str(err) if err else "Unknown Error, see logs" - ) + except (APIError, APIForbidden, HassioError) as err: + return api_return_error(error=err) if isinstance(answer, dict): return api_return_ok(data=answer) @@ -100,10 +97,17 @@ def api_process_raw(content): return wrap_method -def api_return_error(message: Optional[str] = None) -> web.Response: +def api_return_error(error: Optional[Any] = None) -> web.Response: """Return an API error message.""" + message = get_message_from_exception_chain(error) + if check_exception_chain(error, DockerAPIError): + message = format_message(message) return web.json_response( - {JSON_RESULT: RESULT_ERROR, JSON_MESSAGE: format_message(message)}, status=400 + { + JSON_RESULT: RESULT_ERROR, + JSON_MESSAGE: message or "Unknown error, see supervisor", + }, + status=400, ) diff --git a/supervisor/utils/__init__.py b/supervisor/utils/__init__.py index ff1078100..ca7bc9d6c 100644 --- a/supervisor/utils/__init__.py +++ b/supervisor/utils/__init__.py @@ -121,3 +121,14 @@ def check_exception_chain(err: Exception, object_type: Any) -> bool: return False return check_exception_chain(err.__context__, object_type) + + +def get_message_from_exception_chain(err: Exception) -> str: + """Get the first message from the exception chain.""" + if str(err): + return str(err) + + if not err.__context__: + return "" + + return get_message_from_exception_chain(err.__context__) diff --git a/tests/utils/test_exception_helper.py b/tests/utils/test_exception_helper.py index 71b424fa2..05036ab04 100644 --- a/tests/utils/test_exception_helper.py +++ b/tests/utils/test_exception_helper.py @@ -1,6 +1,6 @@ """Test exception helpers.""" -from supervisor.utils import check_exception_chain +from supervisor.utils import check_exception_chain, get_message_from_exception_chain def test_simple_chain_exception(): @@ -55,3 +55,33 @@ def test_list_nested_chain_exception_not(): raise KeyError() from err except KeyError as err: assert not check_exception_chain(err, (AssertionError, OSError)) + + +def test_simple_chain_exception_message(): + """Test simple chain of excepiton.""" + + try: + raise ValueError("error") + except ValueError as err: + assert get_message_from_exception_chain(err) == "error" + + +def test_simple_chain_exception_not_message(): + """Test simple chain of excepiton.""" + + try: + raise ValueError() + except ValueError as err: + assert not get_message_from_exception_chain(err) + + +def test_simple_nested_chain_exception_message(): + """Test simple nested chain of excepiton.""" + + try: + try: + raise ValueError("error") + except ValueError as err: + raise KeyError() from err + except KeyError as err: + assert get_message_from_exception_chain(err) == "error"