Justson/AgentWeb · error · JsCallbackException

the JsCallback isn't permanent,cannot be called more than…

Error message

the JsCallback isn't permanent,cannot be called more than once

What it means

JsCallback.apply throws JsCallbackException when the callback is not permanent (mCouldGoOn == false) and apply() is called a second time. Non-permanent callbacks are single-use: the first apply() already ended the JS call chain (invoking the native completion on the JS side).

Solutions

  1. Call apply() at most once per JsCallback; pass all data in that single invocation
  2. For multiple invocations use the permanent-callback API (permanentCallback()/call()) so mCouldGoOn stays true
  3. Track a boolean 'called' flag around the callback usage
  4. Catch JsCallbackException on repeat calls and log instead of crashing

Example fix

// before
for (Item it : items) { callback.apply(it); } // second apply throws
// after
callback.permanentCallback();
for (Item it : items) { callback.call(it); }
Defensive patterns

Strategy: try-catch

Validate before calling

if (!firstCall) { return; } // guard one-shot callback with a flag

Try / catch

try { callback.apply(result); } catch (JsCallbackException e) { Log.w(TAG, "one-shot callback reused", e); }

Prevention

When it happens

Trigger: Calling apply() twice on the same JsCallback returned for a one-shot JS native method (any callback not marked permanent), or retrying apply() after a failed first invocation.

Common situations: Looping over results and calling apply per item with a one-shot callback (should use permanentCallback + call() semantics instead), retry logic that re-invokes apply on exception, or duplicated event delivery calling the same callback twice.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of Justson/AgentWeb@8f7f6adbf0 (2026-09-11). Data as JSON: /api/errors/863f8e0c8073777f. Report an issue: GitHub.

Appendix: source

Thrown at agentweb-core/src/main/java/com/just/agentweb/JsCallback.java:54

    public JsCallback(WebView view, String injectedName, int index) {
        mCouldGoOn = true;
        mWebViewRef = new WeakReference<WebView>(view);
        mInjectedName = injectedName;
        mIndex = index;
    }

    /**
     * 向网页执行js回调;
     * @param args
     * @throws JsCallbackException
     */
    public void apply (Object... args) throws JsCallbackException {
        if (mWebViewRef.get() == null) {
            throw new JsCallbackException("the WebView related to the JsCallback has been recycled");
        }
        if (!mCouldGoOn) {
            throw new JsCallbackException("the JsCallback isn't permanent,cannot be called more than once");
        }
        StringBuilder sb = new StringBuilder();
        for (Object arg : args){
            sb.append(",");
            boolean isStrArg = arg instanceof String;
            // 有的接口将Json对象转换成了String返回,这里不能加双引号,否则网页会认为是String而不是JavaScript对象;
            boolean isObjArg = isJavaScriptObject(arg);
            if (isStrArg && !isObjArg) {
                sb.append("\"");
            }
            sb.append(String.valueOf(arg));
            if (isStrArg && !isObjArg) {
                sb.append("\"");
            }
        }
        String execJs = String.format(CALLBACK_JS_FORMAT, mInjectedName, mIndex, mIsPermanent, sb.toString());
        if (LogUtils.isDebug()) {
            Log.d("JsCallBack", execJs);

View on GitHub (pinned to 8f7f6adbf0)