From 918185fda41aad45c2ad7ff2bdff674fb63614f0 Mon Sep 17 00:00:00 2001 From: Erik Date: Tue, 21 Apr 2026 10:01:08 +0200 Subject: [PATCH] Extend script continue_on_error suppression when calling actions --- homeassistant/helpers/script.py | 52 ++++++++++++++++++--------------- tests/helpers/test_script.py | 10 +++---- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index 98f23ecd47e7..ee3ff50d990f 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -137,6 +137,17 @@ DEFAULT_MAX_EXCEEDED = "WARNING" ATTR_CUR = "current" ATTR_MAX = "max" +# Configuration errors which should cause the script to stop also when +# continue_on_error is True. +CONFIGURATION_ERRORS = ( + vol.Invalid, + exceptions.TemplateError, + exceptions.ServiceNotFound, + exceptions.InvalidEntityFormatError, + exceptions.NoEntitySpecifiedError, + exceptions.ConditionError, +) + DATA_SCRIPTS: HassKey[list[ScriptData]] = HassKey("helpers.script") DATA_SCRIPT_BREAKPOINTS: HassKey[dict[str, dict[str, set[str]]]] = HassKey( "helpers.script_breakpoints" @@ -566,19 +577,9 @@ class _ScriptRun: if isinstance(exception, _StopScript): raise exception - # These are incorrect scripts, and not runtime errors that need to - # be handled and thus cannot be stopped by `continue_on_error`. - if isinstance( - exception, - ( - vol.Invalid, - exceptions.TemplateError, - exceptions.ServiceNotFound, - exceptions.InvalidEntityFormatError, - exceptions.NoEntitySpecifiedError, - exceptions.ConditionError, - ), - ): + # These are configuration errors which should cause the script to + # stop also when `continue_on_error` is True. + if isinstance(exception, CONFIGURATION_ERRORS): raise exception # Only Home Assistant errors can be ignored. @@ -1015,17 +1016,22 @@ class _ScriptRun: params[CONF_DOMAIN] == "automation" and params[CONF_SERVICE] == "trigger" ) or params[CONF_DOMAIN] in ("python_script", "script") trace_set_result(params=params, running_script=running_script) - response_data = await self._async_run_long_action( - self._hass.async_create_task_internal( - self._hass.services.async_call( - **params, - blocking=True, - context=self._context, - return_response=return_response, - ), - eager_start=True, + try: + response_data = await self._async_run_long_action( + self._hass.async_create_task_internal( + self._hass.services.async_call( + **params, + blocking=True, + context=self._context, + return_response=return_response, + ), + eager_start=True, + ) ) - ) + except (*CONFIGURATION_ERRORS, exceptions.HomeAssistantError): + raise + except Exception as ex: + raise exceptions.HomeAssistantError(ex) from ex if response_variable: self._variables[response_variable] = response_data diff --git a/tests/helpers/test_script.py b/tests/helpers/test_script.py index c0eae4106432..216aa7d191ad 100644 --- a/tests/helpers/test_script.py +++ b/tests/helpers/test_script.py @@ -4153,7 +4153,7 @@ async def test_propagate_error_service_exception(hass: HomeAssistant) -> None: sequence = cv.SCRIPT_SCHEMA([{"action": "test.script"}, {"event": event}]) script_obj = script.Script(hass, sequence, "Test Name", "test_domain") - with pytest.raises(ValueError): + with pytest.raises(exceptions.HomeAssistantError, match="BROKEN"): await script_obj.async_run(context=Context()) assert len(events) == 0 @@ -6324,7 +6324,7 @@ async def test_continue_on_error_automation_issue(hass: HomeAssistant) -> None: async def test_continue_on_error_unknown_error(hass: HomeAssistant) -> None: - """Test continue on error doesn't block unknown errors from e.g., libraries.""" + """Test continue_on_error with unknown errors bubbling up from service calls.""" class MyLibraryError(Exception): """My custom library error.""" @@ -6346,14 +6346,12 @@ async def test_continue_on_error_unknown_error(hass: HomeAssistant) -> None: ) script_obj = script.Script(hass, sequence, "Test Name", "test_domain") - with pytest.raises(MyLibraryError): - await script_obj.async_run(context=Context()) + await script_obj.async_run(context=Context()) assert_action_trace( { "0": [ { - "error": "It is not working!", "result": { "params": { "domain": "some", @@ -6366,7 +6364,7 @@ async def test_continue_on_error_unknown_error(hass: HomeAssistant) -> None: } ], }, - expected_script_execution="error", + expected_script_execution="finished", )