home-assistant/core · error · AbortFlow

cannot_connect

cannot_connect

Error message

cannot_connect

What it means

AbortFlow with reason 'cannot_connect' raised in the Airzone local integration's config flow (discovered-connection step). After discovery finds the device, the flow calls airzone.get_version() to verify the local API is reachable; any AirzoneError or TimeoutError aborts setup with 'cannot_connect'. AbortFlow is not an error surfaced to the user as an exception — HA renders it as a discovery flow message keyed by the reason string.

Source

Thrown at homeassistant/components/airzone/config_flow.py:125

        self._discovered_mac = discovery_info.macaddress

        _LOGGER.debug(
            "DHCP discovery detected Airzone WebServer: %s", self._discovered_mac
        )

        self._async_abort_entries_match({CONF_HOST: self._discovered_ip})

        await self.async_set_unique_id(format_mac(self._discovered_mac))
        self._abort_if_unique_id_configured()

        options = ConnectionOptions(self._discovered_ip)
        airzone = AirzoneLocalApi(
            aiohttp_client.async_get_clientsession(self.hass), options
        )
        try:
            await airzone.get_version()
        except (AirzoneError, TimeoutError) as err:
            raise AbortFlow("cannot_connect") from err

        return await self.async_step_discovered_connection()

    async def async_step_discovered_connection(
        self, user_input: dict[str, Any] | None = None
    ) -> ConfigFlowResult:
        """Confirm discovery."""
        assert self._discovered_ip is not None
        assert self._discovered_mac is not None

        errors = {}
        base_schema = {vol.Required(CONF_PORT, default=DEFAULT_PORT): int}

        if user_input is not None:
            airzone = AirzoneLocalApi(
                aiohttp_client.async_get_clientsession(self.hass),
                ConnectionOptions(
                    self._discovered_ip,

View on GitHub (pinned to 58a3fdb3ea)

Solutions

  1. Verify the Airzone WebServer is reachable from the HA host: curl http://<ip>:3000/api/v1/hvac (or the integration's documented endpoint).
  2. Confirm no duplicate config entry already uses that host (the flow aborts for duplicates just above this code, but leftover entries cause confusion).
  3. Check firewall/VLAN rules allowing HTTP from HA to the device, then retry discovery.
  4. If the IP is stale, reserve a static DHCP lease for the WebServer and rediscover.
Defensive patterns

Strategy: retry

Validate before calling

import asyncio, aiohttp

async def webserver_reachable(ip: str) -> bool:
    try:
        async with aiohttp.ClientSession() as s, asyncio.timeout(5):
            async with s.get(f"http://{ip}:3000/api/v1/hvac") as r:
                return r.status == 200
    except (aiohttp.ClientError, TimeoutError):
        return False

Try / catch

from homeassistant.data_entry_flow import AbortFlow

try:
    await hass.config_entries.flow.async_configure(flow_id, user_input)
except AbortFlow as err:
    if err.reason == "cannot_connect":
        # prompt user to check device/network and retry discovery
        ...

Prevention

When it happens

Trigger: Discovery finds an Airzone WebServer at _discovered_ip but the HTTP GET to its API (get_version) fails: wrong/unreachable IP, WebServer firmware blocking the API, port 3000 not reachable (though default is checked later), device rebooting, or the request exceeding the library timeout.

Common situations: mDNS discovery returning a stale IP after DHCP reassignment; VLAN/IGMP isolation between the HA host and the HVAC network; Airzone WebServer with old firmware that requires a different endpoint; device powered off mid-discovery.

Related errors


AI-assisted analysis of home-assistant/core@58a3fdb3ea (2026-08-14). Data as JSON: /api/errors/f627e29ea9aa0615. Report an issue: GitHub.