Two related defects in AulaChildClient.update_data(), both triggered when Aula
returns a non-JSON body (session expiry, rate limiting, or an Aula outage serving an
HTML error page). Line numbers are against main @ 4a0e7f2 / release v0.1.66.
Observed on Aula 0.1.66, Home Assistant 2026.8.1, ZHA/HAOS, two children at a school
that exposes neither widget 0030 nor 0023.
Problem 1 — a failed MU Opgaver call aborts the entire update, silently skipping ugeplaner
client.py:940-951:
if self._mu_opgaver is True:
try:
guardian = self._session.get(
self.apiurl
+ "?method=profiles.getProfileContext&portalrole=guardian"
+ self._get_access_token_param(),
verify=True,
).json()["data"]["userId"]
except Exception as e:
_LOGGER.warning(
f"Error retrieving MU Opgaver: Empty or ambiguous response: {e}"
)
return # <-- returns from update_data(), not from the MU section
That is a bare return out of update_data(). The Ugeplaner block lives below it at
client.py:1007, so a failure in MU Opgaver means ugeplan/ugeplan_next are never
refreshed on that cycle. Nothing in the log connects the two — the only trace is a
WARNING naming MU Opgaver, while the visible symptom is stale schedule data:
WARNING (SyncWorker_3) [custom_components.aula.client] Error retrieving MU Opgaver: Empty or ambiguous response: Expecting value: line 1 column 1 (char 0)
This is worst for users who have mu_opgaver enabled but whose school exposes no
supported widget: the feature can never return anything (mu_opgaver attribute reads
"Min Uddannelse Opgaver not available"), yet its failure path still takes down the
schedule data that does work.
Suggested fix: scope the early exit to the MU section so one optional feature cannot
abort the others — e.g. wrap the MU block in its own function and return from that,
or replace the bare return with a flag that skips only the MU work.
Problem 2 — unguarded .json() in the ugeplaner block takes all entities unavailable
client.py:1007-1017:
if self._ugeplan is True:
guardian_response = self._session.get(
self.apiurl
+ "?method=profiles.getProfileContext&portalrole=guardian"
+ self._get_access_token_param(),
verify=True,
).json() # <-- not guarded
guardian_data = guardian_response.get("data") if guardian_response else None
if not guardian_data or "userId" not in guardian_data:
_LOGGER.warning("Could not get guardian userId for ugeplaner")
return True
The .get("data") result is carefully null-checked on the next line, but the .json()
call itself is not protected. On a non-JSON body it raises
json.decoder.JSONDecodeError, which propagates out of update_data() into the
DataUpdateCoordinator created in sensor.py:65, so the coordinator marks the update
failed and every Aula entity goes unavailable:
ERROR (MainThread) [custom_components.aula.sensor] Error requesting sensor data: Expecting value: line 1 column 1 (char 0)
Note the MU Opgaver block at line 940 already wraps the identical request in
try/except — the guard is just missing here.
Suggested fix: wrap in try/except and fall through to the existing
"Could not get guardian userId for ugeplaner" path, so a transient Aula hiccup leaves
the previous values in place instead of dropping every entity to unavailable.
Why this combination bites
With both defects present, a single bad reply from Aula either silently skips the
schedule refresh (Problem 1) or drops every entity to unavailable (Problem 2).
Downstream automations that read ugeplan — in my case a TTS announcement of the
kids' timetable each morning — then have to treat "integration is briefly unhealthy"
and "no school today" as the same state.
Happy to open a PR for either or both if the maintainers would like.
Two related defects in
AulaChildClient.update_data(), both triggered when Aulareturns a non-JSON body (session expiry, rate limiting, or an Aula outage serving an
HTML error page). Line numbers are against
main@ 4a0e7f2 / release v0.1.66.Observed on Aula 0.1.66, Home Assistant 2026.8.1, ZHA/HAOS, two children at a school
that exposes neither widget
0030nor0023.Problem 1 — a failed MU Opgaver call aborts the entire update, silently skipping ugeplaner
client.py:940-951:That is a bare
returnout ofupdate_data(). The Ugeplaner block lives below it atclient.py:1007, so a failure in MU Opgaver means ugeplan/ugeplan_next are neverrefreshed on that cycle. Nothing in the log connects the two — the only trace is a
WARNINGnaming MU Opgaver, while the visible symptom is stale schedule data:This is worst for users who have
mu_opgaverenabled but whose school exposes nosupported widget: the feature can never return anything (
mu_opgaverattribute reads"Min Uddannelse Opgaver not available"), yet its failure path still takes down theschedule data that does work.
Suggested fix: scope the early exit to the MU section so one optional feature cannot
abort the others — e.g. wrap the MU block in its own function and
returnfrom that,or replace the bare
returnwith a flag that skips only the MU work.Problem 2 — unguarded
.json()in the ugeplaner block takes all entities unavailableclient.py:1007-1017:The
.get("data")result is carefully null-checked on the next line, but the.json()call itself is not protected. On a non-JSON body it raises
json.decoder.JSONDecodeError, which propagates out ofupdate_data()into theDataUpdateCoordinatorcreated insensor.py:65, so the coordinator marks the updatefailed and every Aula entity goes
unavailable:Note the MU Opgaver block at line 940 already wraps the identical request in
try/except— the guard is just missing here.Suggested fix: wrap in
try/exceptand fall through to the existing"Could not get guardian userId for ugeplaner"path, so a transient Aula hiccup leavesthe previous values in place instead of dropping every entity to
unavailable.Why this combination bites
With both defects present, a single bad reply from Aula either silently skips the
schedule refresh (Problem 1) or drops every entity to
unavailable(Problem 2).Downstream automations that read
ugeplan— in my case a TTS announcement of thekids' timetable each morning — then have to treat "integration is briefly unhealthy"
and "no school today" as the same state.
Happy to open a PR for either or both if the maintainers would like.