From 444772c959a9dc654c7192201ccf4c16c5779556 Mon Sep 17 00:00:00 2001 From: Scarriffle Date: Fri, 3 Jul 2026 21:31:26 +0200 Subject: [PATCH] fix: attribute account-level token failures to each calendar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a Home Assistant or Google token refresh fails, the whole account fetch aborts. Previously this raised, so the outer handler in caldav_router emitted a single sync error WITH NO calendar_id. Clients that preserve cached events per calendar (iOS) couldn't attribute it and wiped the affected calendars. Now both get_ha_events and get_google_events catch the token failure and emit one error per enabled calendar, each carrying its calendar_id — so every client can pin the failure to a specific calendar and keep its cached data. Co-Authored-By: Claude Sonnet 4.6 --- backend/routers/google_router.py | 20 +++++++++++++++++--- backend/routers/homeassistant_router.py | 14 +++++++++++++- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/backend/routers/google_router.py b/backend/routers/google_router.py index f63f35c..f67384f 100644 --- a/backend/routers/google_router.py +++ b/backend/routers/google_router.py @@ -389,14 +389,28 @@ def get_google_events(account: models.GoogleAccount, start_dt: datetime, end_dt: {"source": "google", "name": ..., "message": ...} dicts for any calendar that failed to sync. Never includes raw exception text. """ + all_events = [] + errors = [] try: token = _refresh_access_token(account, db) except Exception as exc: + # A token failure aborts the whole account, but attribute it to each + # enabled calendar so clients can pin the error to a specific calendar + # (and preserve that calendar's cached events instead of wiping it). logger.error("Token refresh failed for Google account %s: %s", account.email, exc) - raise + for gcal in account.calendars: + if not gcal.enabled or gcal.sidebar_hidden: + continue + if _is_system_calendar(gcal.cal_id): + continue + errors.append({ + "source": "google", + "name": f"{account.email} – {gcal.name}", + "calendar_id": gcal.id, + "message": "Sync fehlgeschlagen", + }) + return all_events, errors - all_events = [] - errors = [] for gcal in account.calendars: if not gcal.enabled or gcal.sidebar_hidden: continue diff --git a/backend/routers/homeassistant_router.py b/backend/routers/homeassistant_router.py index b9c112e..4eb5b6a 100644 --- a/backend/routers/homeassistant_router.py +++ b/backend/routers/homeassistant_router.py @@ -325,8 +325,20 @@ def get_ha_events(account: models.HomeAssistantAccount, start_dt: datetime, end_ try: token = _get_valid_token(account, db) except Exception as exc: + # A token failure aborts the whole account, but attribute it to each + # enabled calendar so clients can pin the error to a specific calendar + # (and preserve that calendar's cached events instead of wiping it). logger.error("HA token error for %s: %s", account.name, exc) - raise + for cal in account.calendars: + if not cal.enabled or cal.sidebar_hidden: + continue + errors.append({ + "source": "homeassistant", + "name": f"{account.name} – {cal.name}", + "calendar_id": cal.id, + "message": "Sync fehlgeschlagen", + }) + return all_events, errors for cal in account.calendars: if not cal.enabled or cal.sidebar_hidden: continue