Skip to content

Add a Debug screen with crash history, and stop the HA sync crashing the app - #6

Merged
TargetCrafter merged 1 commit into
mainfrom
fix/crash-visibility
Sep 7, 2026
Merged

TargetCrafter merged 1 commit into
mainfrom
fix/crash-visibility

Conversation

@TargetCrafter

@TargetCrafter TargetCrafter commented Sep 7, 2026 •

Copy link
Copy Markdown
Owner

Why this is very likely the whole thing

A repeatedly crashing app gets force-stopped by Android — and a force-stop cancels every AlarmManager entry the app owned. That is exactly the failure being chased: an alarm that silently stops existing overnight, with the app's own database still showing it as enabled.

It fits every observation: short alarms ring (app alive), long ones don't, the native alarm indicator disappears while our widget still shows the alarm, binary_sensor.*_ringing never fires, and there are no logs — because the entry was gone before the trigger time.

Settings → Debug

Crashes readable from the phone, no adb:

  • Crash history — the last ten, newest first. A list rather than only the newest, because the failure worth diagnosing is a loop, and the first crash in one is usually the informative entry while later ones are knock-on damage.
  • Each is expandable to a monospaced, horizontally scrollable, selectable trace — a stack trace wrapped at phone width is unreadable — with a per-crash copy button.
  • "Copy full diagnostics" puts everything in one block: app version, device and Android build, battery-optimization exemption, background-restricted state and standby bucket, full-screen intent permission, alarm volume, every enabled alarm with its next trigger, whether Android actually holds that schedule, how many times it has dropped it, and all stack traces.

That last one is the point. Chasing this one screenshot at a time is what made it slow; now it's a single paste.

Reachable from a permanent Settings entry, and from the crash warning in Alarm reliability when there's something to look at.

A path that produces exactly this crash

HaApiClient.pushSync built its Request outside the try, and Request.Builder.url throws IllegalArgumentException on a malformed base URL — which is typed by hand. The catch covered only IOException, so anything else escaped into HaSyncService's lifecycleScope, which has no exception handler, killing the process. That loop re-runs on every state change and every service start, so it would crash repeatedly.

Fixed: request built inside the try, non-IOException caught and logged, the collect body guarded, and HaSyncPayload no longer calls nextTriggerAtMillis() on rows that would throw.

Honest status

I have not confirmed the crash you're seeing is this one — that's what the Debug screen is for. Three times I've been confident and wrong; what's different is that this build reports rather than leaving me to infer.

Not verified

Uncompiled here — ./gradlew assembleDebug first.

The app is reportedly crashing repeatedly. That matters beyond the crash
itself: repeated crashes get an app force-stopped, and a force-stop
cancels every AlarmManager entry it owned - which is exactly the failure
being chased, an alarm that silently stops existing overnight.

Makes crashes visible. This build is sideloaded, so nothing collects
crashes and reading logcat needs a computer and a cable, leaving a
background crash completely invisible from the phone. CrashRecorder
stores the last stack trace and Settings shows it with a copy button.
The handler chains to the previous one, so the system still behaves
exactly as before.

Fixes a path that could produce one. HaApiClient.pushSync built its
Request outside the try, and Request.Builder.url throws
IllegalArgumentException on a malformed base URL - which the user types
by hand - while the catch covered only IOException. Anything else
escaped into HaSyncService's lifecycleScope, which has no exception
handler, killing the process. That loop re-runs on every state change
and every service start, so it would crash again and again. The request
is now built inside the try, non-IO exceptions are caught and logged,
the collect body is guarded, and HaSyncPayload no longer calls
nextTriggerAtMillis on rows that would throw.

Whether this is the crash being seen is unconfirmed - that is what the
recorder is for.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01C7x8v5c5Lu29PBWy1LdfCe
@TargetCrafter
TargetCrafter merged commit 723509e into main Sep 7, 2026
4 checks passed
@TargetCrafter
TargetCrafter deleted the fix/crash-visibility branch September 7, 2026 20:35
@TargetCrafter TargetCrafter changed the title Record crashes where they can be read, and stop the HA sync causing them Add a Debug screen with crash history, and stop the HA sync crashing the app Sep 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants