karatelabs/karate · info

dialog handler did not resolve dialog, auto-dismissing

Error message

dialog handler did not resolve dialog, auto-dismissing

What it means

When a JS dialog (alert/confirm/prompt) fires, CdpDriver invokes any user-registered dialog handler. If after the handler runs the dialog is still unhandled, the driver logs this warning and auto-dismisses it so the page cannot stay blocked. A final failure to dismiss is traced only, since a race may have resolved it already.

Solutions

  1. Register a dialog handler (dialog.handle(dialog -> dialog.accept()) or dismiss) in the feature/script so Karate does not auto-dismiss
  2. Ensure the handler always calls accept() or dismiss() on every branch, including error paths
  3. If the dialog is unexpected, fix the page or suppress dialogs in test mode
  4. If auto-dismiss races and hangs, update Karate — newer versions bound the dismiss

Example fix

// before
// no dialog handler registered; alert blocks scenario
// after
driver.handleDialog(dialog -> dialog.accept());
Defensive patterns

Strategy: try-catch

Validate before calling

// declare dialog policy up front in test setup
driver.handleDialog(dialog -> dialog.accept());

Try / catch

try { scenario.actionThatMayAlert(); } catch (Exception e) {
    // dialog was auto-dismissed; assert state accordingly
}

Prevention

When it happens

Trigger: A page under test opens alert()/confirm()/beforeunload dialogs and either no dialog handler is registered or the registered handler does not call accept()/dismiss() before returning.

Common situations: beforeunload prompts appearing during navigation teardown; test forgot to mock/accept an expected alert; handler threw an error (logged via 'dialog handler error') leaving the dialog open.

Related errors


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/3e51fd1c75979f62. Report an issue: GitHub.

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/driver/cdp/CdpDriver.java:950

                    dialogHandler.handle(dialog);
                } catch (Exception e) {
                    // A handler that calls accept()/dismiss() can lose a race with the
                    // dialog already being gone — auto-dismissed, or resolved by another
                    // event on the cdp-event thread — for which CDP returns "No dialog is
                    // showing" (-32602). That is benign (the dialog IS resolved, just not
                    // by this call), so don't surface it at ERROR; only genuine handler
                    // failures should be loud.
                    String msg = e.getMessage();
                    if (msg != null && msg.contains("No dialog is showing")) {
                        logger.debug("dialog handler: dialog already resolved (benign race): {}", msg);
                    } else {
                        logger.error("dialog handler error: {}", msg);
                    }
                }
                // If handler didn't resolve the dialog, auto-dismiss
                // Use local 'dialog' reference, not 'currentDialog' which may be null due to race
                if (!dialog.isHandled()) {
                    logger.warn("dialog handler did not resolve dialog, auto-dismissing");
                    try {
                        dialog.dismiss();
                    } catch (Exception e) {
                        // Dialog may already be gone due to race with another event handler
                        logger.trace("auto-dismiss failed (dialog likely already handled): {}", e.getMessage());
                    }
                }
                // Clear after handling
                currentDialog = null;
                currentDialogText = null;
            }
            if (dialogHandler == null) {
                // A beforeunload prompt ("Leave page?") with no handler registered is
                // always auto-confirmed: it only ever fires on an unload/navigation, so
                // "proceed" is the only sane default. We must NOT gate this on
                // pendingNavigationUrl — that flag is cleared as soon as setUrl returns,
                // and for data:/about: navigations setUrl returns synchronously (no
                // page-load wait), so the gate can already be null by the time the

View on GitHub (pinned to a22eb90246)