diff --git a/esphome/espota2.py b/esphome/espota2.py index 6349ad0fa8..28d9649abd 100644 --- a/esphome/espota2.py +++ b/esphome/espota2.py @@ -154,6 +154,12 @@ def check_error(data: list[int] | bytes, expect: int | list[int] | None) -> None """ if not expect: return + if not data: + raise OTAError( + "Error: Device closed connection without responding. " + "This may indicate the device ran out of memory, " + "a network issue, or the connection was interrupted." + ) dat = data[0] if dat == RESPONSE_ERROR_MAGIC: raise OTAError("Error: Invalid magic byte") diff --git a/tests/unit_tests/test_espota2.py b/tests/unit_tests/test_espota2.py index 02f965782b..1885b769f1 100644 --- a/tests/unit_tests/test_espota2.py +++ b/tests/unit_tests/test_espota2.py @@ -192,6 +192,20 @@ def test_check_error_unexpected_response() -> None: espota2.check_error([0x7F], [espota2.RESPONSE_OK, espota2.RESPONSE_AUTH_OK]) +def test_check_error_empty_data() -> None: + """Test check_error raises error when device closes connection without responding.""" + with pytest.raises( + espota2.OTAError, match="Device closed connection without responding" + ): + espota2.check_error([], [espota2.RESPONSE_OK]) + + # Also test with empty bytes + with pytest.raises( + espota2.OTAError, match="Device closed connection without responding" + ): + espota2.check_error(b"", [espota2.RESPONSE_OK]) + + def test_send_check_with_various_data_types(mock_socket: Mock) -> None: """Test send_check handles different data types."""