home-assistant / home-assistant/android

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

Open
#6,721 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Kotlin
Stars
3.9k
Forks
1.1k
Avg merge
1d 12h
Merged PRs (30d)
81

Description

## 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](https://github.com/home-assistant/android/blob/main/app/src/full/kotlin/io/homeassistant/companion/android/sensors/LocationSensorManager.kt#L1099-L1118)), zone fetching is done per-server inside `ioScope.async` blocks, then collected with `.awaitAll()`:

```kotlin
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`:

```kotlin
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
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.