NSInternalInconsistencyException crash when WKWebView dialog completion handler is not called during ViewController dismissal

Author: nickymalayba-lightspeedCreated May 20, 2026Updated Sep 10, 2026
LabelsType: feature request

A critical crash occurs on iOS when:

  1. A WKWebView presents a JavaScript dialog (alert(), confirm(), or prompt())
  2. The hosting view controller is dismissed before the user interacts with the dialog
  3. The dialog's completion handler is never called

This triggers WebKit's fatal exception:

Fatal Exception: NSInternalInconsistencyException
Completion handler passed to -[RNCWebView webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:] was not called

Real-world impact

This crash manifests in production when:

  • An app presents a modal containing a WebView
  • The modal auto-dismisses after a timeout (e.g., 30 seconds)
  • During the timeout window, a website embedded in the WebView calls window.alert(), window.confirm(), or window.prompt()
  • The user doesn't interact with the dialog before the timeout fires
  • The modal closes and the WebView deallocates with the completion handler still pending
  • The app crashes

Platform: iOS only

Describe the solutions you came up with

The fix implements a call-once wrapper pattern with safe dealloc cleanup:

Solution Components

  1. Add pending handler storage (iOS only)

    • New property: _pendingJSDialogCompletionHandler to track active dialog handlers
  2. Implement call-once guards in three dialog methods:

    • runJavaScriptAlertPanelWithMessage:completionHandler:
    • runJavaScriptConfirmPanelWithMessage:completionHandler:
    • runJavaScriptTextInputPanelWithPrompt:completionHandler:

    Each method now:

    • Creates a callOnce closure that ensures the handler is called exactly once
    • Validates that a view controller is available before presenting
    • Stores the handler for cleanup during dealloc
    • Clears the handler reference after calling to prevent reentry
  3. Add dealloc cleanup

    • If a pending handler exists when the view is deallocated, safely invoke it on the main thread
    • Prevents WebKit's fatal exception

Benefits

  • ✅ Eliminates crash when modal is dismissed with pending JS dialogs
  • ✅ Guarantees completion handler is called exactly once (WebKit requirement)
  • ✅ Thread-safe (dispatches to main queue if necessary)
  • ✅ Zero impact on normal dialog flow (user closes dialog first)
  • ✅ Graceful degradation (safe fallback when view controller is unavailable)

Additional context

  • Affected versions: All versions with WKWebView dialog support
  • Severity: High (production crash)
  • Frequency: Depends on app behavior; easily reproduced in apps with modal timeouts and WebView content

How to reproduce

  1. Create a React Native app with a modal that auto-dismisses after 30 seconds
  2. Load a website in a WKWebView inside that modal like w3schools
  3. Have the website call window.alert() or window.confirm()
  4. Wait 30 seconds without dismissing the dialog
  5. Observe: App crashes with NSInternalInconsistencyException

Code fix reference

See attached patch for the complete implementation covering all three dialog delegate methods.

react-native-webview-npm-13.16.0-82f4e13202.patch

Source: react-native-webview/react-native-webview