diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index 84771509c95..c596b71e691 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -2096,6 +2096,25 @@ class ConfigEntries: _setter = object.__setattr__ if unique_id is not UNDEFINED and entry.unique_id != unique_id: + # Deprecated in 2024.11, should fail in 2025.11 + if ( + unique_id is not None + and self.async_entry_for_domain_unique_id(entry.domain, unique_id) + is not None + ): + report_issue = async_suggest_report_issue( + self.hass, integration_domain=entry.domain + ) + _LOGGER.error( + ( + "Unique id of config entry '%s' from integration %s changed to" + " '%s' which is already in use, please %s" + ), + entry.title, + entry.domain, + unique_id, + report_issue, + ) # Reindex the entry if the unique_id has changed self._entries.update_unique_id(entry, unique_id) changed = True diff --git a/tests/test_config_entries.py b/tests/test_config_entries.py index ed350f4d887..2d2ee2d936a 100644 --- a/tests/test_config_entries.py +++ b/tests/test_config_entries.py @@ -6788,3 +6788,31 @@ async def test_state_cache_is_cleared_on_entry_disable(hass: HomeAssistant) -> N ) loaded = json_loads(json_dumps(entry.as_json_fragment)) assert loaded["disabled_by"] == "user" + + +async def test_async_update_entry_unique_id_collision( + hass: HomeAssistant, + manager: config_entries.ConfigEntries, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test we warn when async_update_entry creates a unique_id collision.""" + + entry1 = MockConfigEntry(domain="test", unique_id=None) + entry2 = MockConfigEntry(domain="test", unique_id="not none") + entry3 = MockConfigEntry(domain="test", unique_id="very unique") + entry4 = MockConfigEntry(domain="test", unique_id="also very unique") + entry1.add_to_manager(manager) + entry2.add_to_manager(manager) + entry3.add_to_manager(manager) + entry4.add_to_manager(manager) + + manager.async_update_entry(entry2, unique_id=None) + assert len(caplog.record_tuples) == 0 + + manager.async_update_entry(entry4, unique_id="very unique") + assert len(caplog.record_tuples) == 1 + + assert ( + "Unique id of config entry 'Mock Title' from integration test changed to " + "'very unique' which is already in use" + ) in caplog.text