Skip to content

fix(webview): surface main-frame load failures in the in-app browser#61

Open
jim-daf wants to merge 1 commit into
bernaferrari:masterfrom
jim-daf:fix-webview-onreceivederror
Open

fix(webview): surface main-frame load failures in the in-app browser#61
jim-daf wants to merge 1 commit into
bernaferrari:masterfrom
jim-daf:fix-webview-onreceivederror

Conversation

@jim-daf
Copy link
Copy Markdown

@jim-daf jim-daf commented May 15, 2026

Closes #60.

The in-app browser WebViewFragment (app/src/main/java/com/bernaferrari/changedetection/addedit/WebViewFragment.kt:48) overrides onPageStarted and onPageFinished to drive the progress bar but does not override onReceivedError. When the user types a URL that fails to load (DNS error, offline, certificate issue, 4xx/5xx) the WebView is left showing a blank area with no indication of what went wrong.

Add an onReceivedError override that hides the progress bar and shows a short Toast with the failure reason on main-frame failures only (so blocked sub-resources do not also pop Toasts):

override fun onReceivedError(
    view: WebView?,
    request: WebResourceRequest?,
    error: WebResourceError?
) {
    super.onReceivedError(view, request, error)
    if (request?.isForMainFrame != true) return
    progress?.visibility = View.GONE
    val description = if (Build.VERSION.SDK_INT >= 23) {
        error?.description?.toString().orEmpty()
    } else {
        ""
    }
    val message = if (description.isNotBlank()) {
        getString(R.string.webview_load_failed_with_reason, description)
    } else {
        getString(R.string.webview_load_failed)
    }
    Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}

Adds two strings (webview_load_failed, webview_load_failed_with_reason) so the message stays translatable. The happy path is unchanged.

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Web pages that fail to load now display error notifications to users, providing clear feedback when loading encounters issues. Error details are included where available.

Review Change Stack

WebViewFragment in addedit/ is the screen the user types or navigates
a URL into so it can be picked for monitoring. The WebViewClient
overrides onPageStarted and onPageFinished to drive the progress bar
but does not override onReceivedError, so a failed navigation (DNS,
certificate, offline, 4xx/5xx) just leaves a blank page with no clue
what went wrong.

Add an onReceivedError override that hides the progress bar and shows
a short Toast with the failure reason. Gated on
request.isForMainFrame so a blocked sub-resource does not also pop a
Toast. Adds webview_load_failed / webview_load_failed_with_reason
strings to keep the message translatable.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

📝 Walkthrough

Walkthrough

WebViewFragment's embedded WebViewClient now handles page-load failures by overriding onReceivedError to dismiss the progress indicator, filter main-frame errors, optionally include the error reason on API 23+, and display a localized toast to the user.

Changes

WebView Error Handling

Layer / File(s) Summary
WebView error handler with localized messages
app/src/main/java/com/bernaferrari/changedetection/addedit/WebViewFragment.kt, app/src/main/res/values/strings.xml
Imports add Build, WebResourceError, and WebResourceRequest. The WebViewClient.onReceivedError override dismisses the progress indicator, filters to main-frame failures, derives an optional error description on API 23+, selects the appropriate localized string (with or without reason), and shows a toast. Two new string resources provide translatable messages for the failure states.

Estimated Code Review Effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐰 A WebView once swallowed its failures in silence,
But now, brave and kind, it speaks up with appliance—
A toast pops, a message appears clear and bright,
When pages won't load, the user's not left in the night! 🌙✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding error handling for main-frame WebView load failures in the in-app browser.
Linked Issues check ✅ Passed The PR fully implements all coding requirements from issue #60: onReceivedError override with main-frame gating, progress bar hiding, error message display via Toast, and translatable string resources.
Out of Scope Changes check ✅ Passed All changes are directly related to issue #60 requirements: WebViewClient.onReceivedError implementation and string resource additions for error messaging.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@app/src/main/java/com/bernaferrari/changedetection/addedit/WebViewFragment.kt`:
- Around line 68-89: The WebViewFragment currently only handles onReceivedError
(main-frame DNS/offline and non-recoverable SSL), but missing handling for HTTP
errors and recoverable SSL errors; implement overrides for
onReceivedHttpError(WebView, WebResourceRequest, WebResourceResponse) to detect
main-frame HTTP 4xx/5xx and show the same progress hide + toast logic (use
getString(R.string.webview_load_failed_with_reason) when response reason/status
available), and override onReceivedSslError(WebView, SslErrorHandler, SslError)
to show a user-facing message (hide progress, show appropriate toast using
getString(...) and include sslError.primaryError or message) and call
handler.cancel() to avoid proceeding on unrecoverable cert issues; reuse the
existing progress and message construction approach from onReceivedError so all
three callbacks provide consistent UX.
- Line 88: In WebViewFragment, the Toast call inside the async WebViewClient
callback uses the Fragment's nullable context directly (Toast.makeText(context,
...)); guard against the Fragment being detached by resolving a safe context
first (e.g., val safeCtx = view?.context ?: context ?: return) or check context
?: return before calling Toast.makeText, then use safeCtx when creating/showing
the Toast to avoid crashes when the callback runs after detach.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 99901c7c-e1d1-4082-bac1-4617cfcc3867

📥 Commits

Reviewing files that changed from the base of the PR and between 4cb31aa and b53fc5e.

📒 Files selected for processing (2)
  • app/src/main/java/com/bernaferrari/changedetection/addedit/WebViewFragment.kt
  • app/src/main/res/values/strings.xml

Comment on lines +68 to +89
override fun onReceivedError(
view: WebView?,
request: WebResourceRequest?,
error: WebResourceError?
) {
super.onReceivedError(view, request, error)
// Only surface the main-frame failure, otherwise every blocked
// sub-resource would pop a toast
if (request?.isForMainFrame != true) return
progress?.visibility = View.GONE
val description = if (Build.VERSION.SDK_INT >= 23) {
error?.description?.toString().orEmpty()
} else {
""
}
val message = if (description.isNotBlank()) {
getString(R.string.webview_load_failed_with_reason, description)
} else {
getString(R.string.webview_load_failed)
}
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Android WebViewClient callback behavior: which callbacks are invoked for main-frame DNS/offline failures, HTTP 4xx/5xx responses, and SSL certificate errors? Please include official Android docs for onReceivedError, onReceivedHttpError, and onReceivedSslError.

💡 Result:

In Android WebView, error handling is managed through specific WebViewClient callbacks. Below is the behavior for the requested scenarios: Main-Frame DNS/Offline Failures These are considered resource loading errors and are handled by onReceivedError. - Callback: onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) [1][2]. - Behavior: This method is invoked when the WebView encounters an unrecoverable error, such as a DNS lookup failure (ERROR_HOST_LOOKUP), connection failure (ERROR_CONNECT), or when the device is offline [3][2]. It is called for any resource (e.g., iframes, images) [2]. To specifically target main-frame failures, you should check the isForMainFrame property of the WebResourceRequest [4]. HTTP 4xx/5xx Responses HTTP errors are handled by a separate callback introduced in API level 23. - Callback: onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) [1][5]. - Behavior: This is invoked when the server returns an HTTP status code >= 400 [1][4]. Like onReceivedError, this callback triggers for any resource, not just the main page [1][4]. You can use request.isForMainFrame to filter for main-frame errors [4]. Note that the server response body may not be available in the errorResponse parameter [1][4]. SSL Certificate Errors SSL errors are handled by onReceivedSslError. - Callback: onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) [1][3]. - Behavior: This is invoked only for recoverable SSL certificate errors [1][5]. The host application must explicitly call handler.cancel or handler.proceed to continue or stop the load [1][3]. For non-recoverable SSL errors (e.g., server fails the client), the WebView will instead call onReceivedError with the ERROR_FAILED_SSL_HANDSHAKE constant [1][5]. Official Documentation References - onReceivedError: https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedError(android.webkit.WebView,%20android.webkit.WebResourceRequest,%20android.webkit.WebResourceError) - onReceivedHttpError: https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedHttpError(android.webkit.WebView,%20android.webkit.WebResourceRequest,%20android.webkit.WebResourceResponse) - onReceivedSslError: https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedSslError(android.webkit.WebView,%20android.webkit.SslErrorHandler,%20android.net.http.SslError)

Citations:


Main-frame failure handling is incomplete for HTTP and SSL error paths.

The current implementation only overrides onReceivedError, which handles DNS/offline failures and non-recoverable SSL errors, but does not handle HTTP 4xx/5xx responses (onReceivedHttpError) or recoverable SSL certificate errors (onReceivedSslError). This leaves users without feedback when the server returns HTTP errors or when certificate validation fails. Both cases are explicitly listed in the PR objective and require separate callbacks to be implemented.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/src/main/java/com/bernaferrari/changedetection/addedit/WebViewFragment.kt`
around lines 68 - 89, The WebViewFragment currently only handles onReceivedError
(main-frame DNS/offline and non-recoverable SSL), but missing handling for HTTP
errors and recoverable SSL errors; implement overrides for
onReceivedHttpError(WebView, WebResourceRequest, WebResourceResponse) to detect
main-frame HTTP 4xx/5xx and show the same progress hide + toast logic (use
getString(R.string.webview_load_failed_with_reason) when response reason/status
available), and override onReceivedSslError(WebView, SslErrorHandler, SslError)
to show a user-facing message (hide progress, show appropriate toast using
getString(...) and include sslError.primaryError or message) and call
handler.cancel() to avoid proceeding on unrecoverable cert issues; reuse the
existing progress and message construction approach from onReceivedError so all
three callbacks provide consistent UX.

} else {
getString(R.string.webview_load_failed)
}
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find and read the WebViewFragment.kt file
find . -name "WebViewFragment.kt" -type f

Repository: bernaferrari/ChangeDetection

Length of output: 152


🏁 Script executed:

#!/bin/bash
# Read the file around line 88 to see the actual context
if [ -f "app/src/main/java/com/bernaferrari/changedetection/addedit/WebViewFragment.kt" ]; then
  wc -l "app/src/main/java/com/bernaferrari/changedetection/addedit/WebViewFragment.kt"
fi

Repository: bernaferrari/ChangeDetection

Length of output: 154


🏁 Script executed:

#!/bin/bash
# Read the file with context around line 88
sed -n '60,110p' "app/src/main/java/com/bernaferrari/changedetection/addedit/WebViewFragment.kt"

Repository: bernaferrari/ChangeDetection

Length of output: 1900


🏁 Script executed:

#!/bin/bash
# Read the entire file to understand the class structure and callback
cat "app/src/main/java/com/bernaferrari/changedetection/addedit/WebViewFragment.kt"

Repository: bernaferrari/ChangeDetection

Length of output: 4814


Guard nullable Fragment context before showing Toast.

Line 88 uses context directly in an async WebViewClient callback; if the Fragment is detached when the callback arrives, this will crash. Prefer view?.context ?: return (or combine with context ?: return) before Toast.makeText.

Suggested patch
-                Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
+                val ctx = view?.context ?: return
+                Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
val ctx = view?.context ?: return
Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/src/main/java/com/bernaferrari/changedetection/addedit/WebViewFragment.kt`
at line 88, In WebViewFragment, the Toast call inside the async WebViewClient
callback uses the Fragment's nullable context directly (Toast.makeText(context,
...)); guard against the Fragment being detached by resolving a safe context
first (e.g., val safeCtx = view?.context ?: context ?: return) or check context
?: return before calling Toast.makeText, then use safeCtx when creating/showing
the Toast to avoid crashes when the callback runs after detach.

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.

In-app browser WebView swallows page-load errors with no indication to the user

1 participant