willowtreeapps / willowtreeapps/vocable-android

ARCore FatalException crash in head-tracking frame loop has no recovery path

Open
#697 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Kotlin
Stars
127
Forks
21
Avg merge
16m
Merged PRs (30d)
4

Description

Why

Play Console reports a production crash on 1.6.1 (build 638): com.google.ar.core.exceptions.FatalException thrown from Session.update(), surfacing as com.google.ar.core.Session.throwExceptionFromArStatus. Currently 1 affected user, 1 event, in the last 28 days (last occurred ~21 hours before this ticket was filed) — low volume, so this is being tracked rather than fixed now.

Traced the call path by decompiling the actual sceneview 2.3.3 bytecode (not just reading the API surface): Choreographer.doFrameSceneView.onFrameARSceneView.onFrameARSession.updateOrNull()Session.update() has no exception handling anywhere in that chain. updateOrNull()'s name is misleading — it only returns null when the session isn't resumed or there's no new frame yet, never when ARCore itself throws. Any exception from Session.update() (this FatalException, but potentially others) propagates straight through the Choreographer callback and crashes the whole app on the main thread. The library does expose a separate onException callback, but it appears to only cover session creation/resume failures, not per-frame update failures — there is no existing hook for this specific crash class.

Per Google's own ARCore documentation, FatalException means the session is in an unrecoverable state and the recommended action is to restart the app — so there is no fix that keeps head tracking working after this hits. The only real remediation is turning a hard, contextless crash into a controlled recovery (e.g. an app-level uncaught-exception handler that detects this specifically and restarts gracefully, or forking/subclassing ARSceneView.onFrame to add a try/catch, which the public ARScene composable API doesn't currently expose a clean way to do).

Scope

Add a recovery path for Session.update() exceptions in the head-tracking frame loop, so a FatalException (or similar) results in a graceful restart/reset of head tracking instead of a full app crash.

Acceptance Criteria

  • Confirm whether a newer sceneview release (current: 2.3.3) has since added exception handling around Session.update() / ARSceneView.onFrame, before building a custom workaround
  • If no upstream fix exists, add a mechanism (app-level uncaught-exception handler scoped to ARCore exceptions, or a custom ARSceneView/frame-callback override) that catches this exception class and recovers without crashing the whole app
  • Recovery behavior should leave the user in a sane state (e.g. head tracking disabled with the existing error banner, or a full but controlled Activity restart) rather than a raw process death
  • Add a note to CLAUDE.md's head-tracking/accessibility section once the mechanism exists, since this is a fragile-area gap in the current architecture notes

Out of Scope

  • Root-causing why this specific device/session hit a FatalException (device/OS-driver-specific ARCore native failure) — not practically diagnosable from a single occurrence; revisit if volume increases
  • Any fix that keeps AR/head tracking functioning after a FatalException — Google's own docs say the session is unrecoverable at that point

Links

(none)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

First verify whether a newer sceneview release handles exceptions in ARSceneView.onFrame or ARSession.updateOrNull(), using the current 2.3.3 dependency as the baseline. Then trace the existing ARSceneView.onFrame → ARSession.updateOrNull() → Session.update() path and choose a recovery point that fits the public API. Done means FatalException no longer causes a raw process crash, recovery leaves head tracking in a sane state, and CLAUDE.md documents the architectural gap.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, kotlin
Domain
mobile-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.