Skip to content

Multi-server: unreachable server breaks geofence registration for all servers #6721

@loganrosen

Description

@loganrosen

Version

  • App: 2026.3.2-full
  • Android: 16 (SDK 36)
  • Phone: Pixel 9 Pro XL

Description

When the app has multiple servers configured and one server is unreachable, createGeofencingRequest() in LocationSensorManager.kt fails for all servers, not just the unreachable one.

Root cause

In createGeofencingRequest() (line 1099-1118), zone fetching is done per-server inside ioScope.async blocks, then collected with .awaitAll():

getEnabledServers(latestContext, zoneLocation).map { serverId ->
    ioScope.async {
        val configuredZones = getZones(serverId, forceRefresh = true)
        // ...
    }
}.awaitAll()

If getZones(serverId) throws for any server (e.g., NoUrlAvailableException because the server is unreachable, or HTTP 410 Gone because the webhook expired), awaitAll() propagates the exception. This crashes the entire function before any geofences are registered — even for servers that are perfectly healthy.

Impact

This completely breaks location tracking (both zone and background) for users with multiple servers when one server becomes unreachable. In my case:

  • Server A: reachable, working correctly
  • Server B: unreachable from current network, webhook returning 410 Gone

The Server B failure prevented any geofences from being registered for Server A. The device tracker was stuck at unknown for days because no location updates were ever sent.

Expected behavior

Zone fetching failures for one server should not prevent geofence registration for other servers. Each server's zones should be fetched independently, with per-server error handling.

Suggested fix

Wrap each server's zone fetch in a try/catch inside the async block, or use supervisorScope:

getEnabledServers(latestContext, zoneLocation).map { serverId ->
    ioScope.async {
        try {
            val configuredZones = getZones(serverId, forceRefresh = true)
            configuredZones.forEach {
                addGeofenceToBuilder(geofencingRequestBuilder, serverId, it)
                geofenceCount++
                // ...
            }
            geofenceRegistered.add(serverId)
        } catch (e: Exception) {
            Timber.e(e, "Failed to fetch zones for server $serverId, skipping")
        }
    }
}.awaitAll()

Logs

D LocationSensorManager: Registering for zone based location updates
E LocationSensorManager: Error receiving zones from Home Assistant
E LocationSensorManager: io.homeassistant.companion.android.common.data.integration.IntegrationException: All URLs failed for get_zones
W LocationSensorManager: No zones, skipping zone based location updates

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions