diff --git a/homeassistant/components/mqtt/models.py b/homeassistant/components/mqtt/models.py index 9afa3de3f48d98..a936c9e420d67f 100644 --- a/homeassistant/components/mqtt/models.py +++ b/homeassistant/components/mqtt/models.py @@ -231,11 +231,21 @@ def async_render_with_possible_json_value( values, self._value_template, ) - rendered_payload = ( - self._value_template.async_render_with_possible_json_value( - payload, variables=values + try: + rendered_payload = ( + self._value_template.async_render_with_possible_json_value( + payload, variables=values + ) ) - ) + except Exception as ex: # pylint: disable=broad-except + _LOGGER.error( + "%s: %s rendering template for entity '%s', template: '%s'", + type(ex).__name__, + ex, + self._entity.entity_id if self._entity else "n/a", + self._value_template.template, + ) + raise ex return rendered_payload _LOGGER.debug( @@ -248,9 +258,24 @@ def async_render_with_possible_json_value( default, self._value_template, ) - rendered_payload = self._value_template.async_render_with_possible_json_value( - payload, default, variables=values - ) + try: + rendered_payload = ( + self._value_template.async_render_with_possible_json_value( + payload, default, variables=values + ) + ) + except Exception as ex: # pylint: disable=broad-except + _LOGGER.error( + "%s: %s rendering template for entity '%s', template: " + "'%s', default value: %s and payload: %s", + type(ex).__name__, + ex, + self._entity.entity_id if self._entity else "n/a", + self._value_template.template, + default, + payload, + ) + raise ex return rendered_payload diff --git a/tests/components/mqtt/test_init.py b/tests/components/mqtt/test_init.py index c0d7a94de5b79f..e3a12a2c24ec80 100644 --- a/tests/components/mqtt/test_init.py +++ b/tests/components/mqtt/test_init.py @@ -41,6 +41,7 @@ from tests.common import ( MockConfigEntry, + MockEntity, async_fire_mqtt_message, async_fire_time_changed, mock_restore_cache, @@ -417,6 +418,37 @@ async def test_value_template_value(hass: HomeAssistant) -> None: assert template_state_calls.call_count == 1 +async def test_value_template_fails( + hass: HomeAssistant, caplog: pytest.LogCaptureFixture +) -> None: + """Test the rendering of MQTT value template fails.""" + + # test rendering a value fails + entity = MockEntity(entity_id="sensor.test") + entity.hass = hass + tpl = template.Template("{{ value_json.some_var * 2 }}") + val_tpl = mqtt.MqttValueTemplate(tpl, hass=hass, entity=entity) + with pytest.raises(TypeError): + val_tpl.async_render_with_possible_json_value('{"some_var": null }') + await hass.async_block_till_done() + assert ( + "TypeError: unsupported operand type(s) for *: 'NoneType' and 'int' " + "rendering template for entity 'sensor.test', " + "template: '{{ value_json.some_var * 2 }}'" + ) in caplog.text + caplog.clear() + with pytest.raises(TypeError): + val_tpl.async_render_with_possible_json_value( + '{"some_var": null }', default=100 + ) + assert ( + "TypeError: unsupported operand type(s) for *: 'NoneType' and 'int' " + "rendering template for entity 'sensor.test', " + "template: '{{ value_json.some_var * 2 }}', default value: 100 and payload: " + '{"some_var": null }' + ) in caplog.text + + async def test_service_call_without_topic_does_not_publish( hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator ) -> None: