Repository navigation
Description
Summary
Confirmed locally, reproduces on this fork's current CEF version (146.0.10+g8219561+chromium-146.0.7680.179): matches upstream chromiumembedded/java-cef#398, still open there, originally reported against CEF 87.1.12 -- still present ~7 major CEF versions later.
The CEF message router's "subscription" style query workflow (JS sets persistent: true in the window.cefQuery() options) is documented to allow CefQueryCallback.success() to be called repeatedly, with each call invoking the JS onSuccess handler again.
native/CefQueryCallback_N.cpp's N_Success unconditionally calls ClearSelf() after the first call, regardless of persistent:
JNIEXPORT void JNICALL
Java_org_cef_callback_CefQueryCallback_1N_N_1Success(JNIEnv* env, jobject obj, jlong self,
jstring response) {
CefRefPtr<CefQueryCallback> callback = GetSelf(self);
if (!callback)
return;
callback->Success(GetJNIString(env, response));
ClearSelf(env, obj); // <-- unconditional, ignores |persistent|
}ClearSelf() nulls the Java-side native handle field, so a second success() call on the same CefQueryCallback object silently no-ops (GetSelf() returns null, the if (!callback) return; guard swallows it) -- not a crash, just silently broken. The JS onSuccess handler is never invoked a second time no matter how many more times Java calls success().
Repro
Added java/tests/junittests/UpstreamIssue398Test.java (currently @Disabled with a link to this issue, so it doesn't fail the normal suite -- remove @Disabled to re-run it):
- Register a
CefMessageRouterHandlerwhoseonQuery()saves theCefQueryCallbackand callscallback.success("first")once for a query sent withpersistent: true. - Once the JS
onSuccesshandler's first invocation is observed (via a title change), callsavedCallback.success("second")again from Java. - Expected: JS
onSuccessfires again with"second". Actual: it never fires again -- the test times out waiting for it (confirmed viaTestFrame's watchdog cleanly force-closing after 10s, not a real hang).
Fix sketch (not implemented here)
N_Success (and likely N_Failure, though Failure ending a query legitimately should always clear regardless of persistent) needs to know whether the original query was persistent, and skip ClearSelf() in that case -- the native CefMessageRouterBrowserSide::Callback itself is designed to support this (that's what upstream's persistent JS flag threads through to on the C++ side); the bug is specifically in this JNI wrapper discarding that distinction.
Found via
This fork's coverage-expansion effort (tracked in #5), while triaging upstream's issue tracker for bugs that could become regression tests in this fork's suite per the user's explicit direction to "start harvesting the upstream git issues for problematic tests."
Activity
Add @disabled regression test for upstream chromiumembedded#398 (fork #…
Thrameos commentedon Aug 31, 2026
Fixed. native/CefQueryCallback_N.cpp's N_Success unconditionally called ClearSelf() after the first call, regardless of whether the originating query was persistent -- so a second success() call on the same callback silently no-op'd (native ref already torn down).
Fix: threaded the
persistentflag (already available in MessageRouterHandler::OnQuery(), matching CEF's own persistent tracking) through to the Java-side CefQueryCallback_N object via a new package-privatesetPersistent()call made right after the callback object is constructed, before onQuery() is invoked. success() now passes that flag to N_Success, which only calls ClearSelf() when the query is not persistent. N_Failure is unchanged -- a failure always ends the query regardless of persistent.Un-disabled the existing UpstreamIssue398Test regression test (previously @disabled with a confirmed-failing reproduction). Verified failing before the fix and passing after.
Fix issue #13: CefQueryCallback.success() ignores persistent=true
Fix issue #13: CefQueryCallback.success() ignores persistent=true
Merge pull request #38 from Thrameos/backport/query-callback-persistent