← Back to PRs

#19548: fix(android): show scaffold instead of raw JSON on canvas auth errors

by gregmousseau open 2026-02-17 23:17 View on GitHub →
app: android size: XS
## Summary Describe the problem and fix in 2–5 bullets: - **Problem:** When the Android app connects, the WebView sometimes loads the canvas URL before authentication is fully established. This results in a raw JSON 401 error displayed to the user: `{"error":{"message":"Unauthoriz ed","type":"unauthorized"}}`. - **Why it matters:** It looks broken/scary to users on first launch or reconnection, even though the app is actually working in the background. - **What changed:** The `WebViewClient` now intercepts HTTP 401/403 errors and generic network errors on the main frame. Instead of showing the raw error, it loads the local `scaffold.html` (blank canvas). The app automatically re-navigates to the correct URL once the session is ready. - **What did NOT change:** No changes to authentication logic or retry mechanisms; purely a UI fallback for the WebView. ## Change Type (select all) - [x] Bug fix - [ ] Feature - [ ] Refactor - [ ] Docs - [ ] Security hardening - [ ] Chore/infra ## Scope (select all touched areas) - [ ] Gateway / orchestration - [ ] Skills / tool execution - [ ] Auth / tokens - [ ] Memory / storage - [ ] Integrations - [ ] API / contracts - [x] UI / DX (Android) - [ ] CI/CD / infra ## Linked Issue/PR - Closes (none) ## User-visible / Behavior Changes - Users will no longer see raw JSON error text on the home screen during connection/auth glitches. - They will see a neutral blank canvas (scaffold) until the app connects and loads the real UI. ## Security Impact (required) - New permissions/capabilities? (No) - Secrets/tokens handling changed? (No) - New/changed network calls? (No) - Command/tool execution surface changed? (No) - Data access scope changed? (No) ## Repro + Verification ### Environment - OS: Android 15 (OnePlus 12) - Runtime: OpenClaw Android App - Gateway: Local dev instance ### Steps 1. Launch app with a valid gateway configured. 2. Force a race condition (or simulate a 401 by invalidating the token temporarily). 3. Observe the WebView behavior. ### Expected - WebView shows blank scaffold or loading state. ### Actual - Before: Raw JSON `{"error":...}` text. - After: Clean scaffold UI. ## Evidence -Previously, error would persist even after resolution: <img width="1438" height="591" alt="image" src="https://github.com/user-attachments/assets/f490154c-9a54-4ce4-a0de-b8ddbf0899cb" /> -Now: <img width="1438" height="564" alt="image" src="https://github.com/user-attachments/assets/9ae85865-b805-497a-8e58-bc671e3e96e0" /> ## Human Verification (required) What you personally verified (not just CI), and how: - Verified on OnePlus 12. - Simulating auth error triggers the fallback path correctly. ## Compatibility / Migration - Backward compatible? (Yes) 🤖 AI-Assisted: Yes (Claude via OpenClaw) <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR fixes a UX issue where Android users would see raw JSON error text (`{"error":{"message":"Unauthorized","type":"unauthorized"}}`) in the WebView during auth race conditions on app start. The fix intercepts HTTP 401/403 errors in `onReceivedHttpError` and all main-frame network errors in `onReceivedError`, loading the local `scaffold.html` as a neutral blank canvas instead. Re-navigation to the correct URL happens through the existing `CanvasController.navigate()` mechanism once the gateway session is established — this PR does not change that flow. **Key changes:** - `onReceivedError`: now loads `scaffold.html` for all main-frame network errors (gateway offline, timeout, etc.) instead of only logging in debug builds. - `onReceivedHttpError`: now loads `scaffold.html` for 401/403 responses instead of only logging in debug builds. - Logging is correctly preserved behind the `isDebuggable` guard. **Minor concern:** - The scaffold asset URL `"file:///android_asset/CanvasScaffold/scaffold.html"` is now duplicated as a string literal in two places in `RootScreen.kt`, while `CanvasController` already holds this string as `private val scaffoldAssetUrl`. Promoting the constant to a `companion object` would keep it DRY across both classes. <h3>Confidence Score: 4/5</h3> - This PR is safe to merge — it is a purely additive UI fallback with no changes to auth logic, token handling, or network calls. - The change is narrow in scope (two callbacks in one file), does not affect authentication or re-connection logic, and the scaffold fallback is already used by `CanvasController` for the default canvas state. The main-frame guard ensures sub-resource errors are unaffected. The only finding is a style-level duplication of the scaffold URL constant. No logic errors or security issues were identified. - No files require special attention beyond the minor duplicate-constant concern in `apps/android/app/src/main/java/ai/openclaw/android/ui/RootScreen.kt`. <sub>Last reviewed commit: 205f446</sub> <!-- greptile_other_comments_section --> <sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub> <!-- /greptile_comment -->

Most Similar PRs