1
0
mirror of https://github.com/home-assistant/core.git synced 2026-07-13 17:44:45 +01:00

Don't log configuration errors when executing WS subscribe_trigger (#172918)

This commit is contained in:
Erik Montnemery
2026-06-03 19:58:32 +02:00
committed by GitHub
parent 2e041dd45f
commit c329bb4000
2 changed files with 115 additions and 1 deletions
@@ -980,7 +980,24 @@ async def handle_subscribe_trigger(
hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
) -> None:
"""Handle subscribe trigger command."""
trigger_config = await async_validate_trigger_config(hass, msg["trigger"])
# Validating the trigger config can fail on bad user input. Handle those
# errors here so they are reported to the client without being logged as
# unexpected errors by the default websocket error handler.
try:
trigger_config = await async_validate_trigger_config(hass, msg["trigger"])
except vol.Invalid as err:
connection.send_error(msg["id"], const.ERR_INVALID_FORMAT, str(err))
return
except HomeAssistantError as err:
connection.send_error(
msg["id"],
const.ERR_HOME_ASSISTANT_ERROR,
str(err),
translation_domain=err.translation_domain,
translation_key=err.translation_key,
translation_placeholders=err.translation_placeholders,
)
return
@callback
def forward_triggers(
@@ -2745,6 +2745,103 @@ async def test_subscribe_trigger(
assert sum(hass.bus.async_listeners().values()) == init_count
@pytest.mark.parametrize(
("trigger", "expected_error"),
[
# Unknown trigger platform
(
{"platform": "nonexistent"},
{
"code": "invalid_format",
"message": "Invalid trigger 'nonexistent' specified",
},
),
# Missing mandatory config for the trigger platform
(
{"platform": "numeric_state"},
{
"code": "invalid_format",
"message": "required key not provided @ data['entity_id']",
},
),
# Unknown device, raised as a HomeAssistantError by the platform validator
(
{"platform": "device", "domain": "light", "device_id": "nonexistent"},
{
"code": "home_assistant_error",
"message": "Unknown device 'nonexistent'",
},
),
],
)
async def test_subscribe_trigger_config_error(
hass: HomeAssistant,
websocket_client: MockHAClientWebSocket,
caplog: pytest.LogCaptureFixture,
trigger: dict,
expected_error: dict,
) -> None:
"""Test trigger config errors are reported to the client without logging."""
caplog.set_level(logging.ERROR)
await websocket_client.send_json_auto_id(
{"type": "subscribe_trigger", "trigger": trigger}
)
msg = await websocket_client.receive_json()
assert msg["type"] == const.TYPE_RESULT
assert not msg["success"]
assert msg["error"] == expected_error
# The expected error is not logged by the default websocket error handler
assert "Error handling message" not in caplog.text
async def test_subscribe_trigger_template_error_spams_log(
hass: HomeAssistant,
websocket_client: MockHAClientWebSocket,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test that a failing trigger template spams the log.
This documents unwanted behavior. Unlike subscribe_condition and
test_condition, subscribe_trigger does not suppress repeated template
variable errors: a trigger is evaluated event-driven by its platform (here
via async_track_template_result), outside any trace context, so the
trace-based suppression used for conditions does not apply. This should be
fixed in the future so the error is suppressed/forwarded instead of being
logged on every re-render.
"""
caplog.set_level(logging.WARNING)
hass.states.async_set("sensor.test", "1")
await websocket_client.send_json_auto_id(
{
"type": "subscribe_trigger",
"trigger": {
"platform": "template",
"value_template": "{{ states('sensor.test') }}{{ undefined_variable }}",
},
}
)
msg = await websocket_client.receive_json()
assert msg["type"] == const.TYPE_RESULT
assert msg["success"]
# Each re-render of the template logs the undefined variable error again
for state in ("2", "3", "4"):
hass.states.async_set("sensor.test", state)
await hass.async_block_till_done()
assert (
caplog.text.count(
"Template variable warning: 'undefined_variable' is undefined"
)
> 1
)
async def test_test_condition(
hass: HomeAssistant, websocket_client: MockHAClientWebSocket
) -> None: