java-native-access/jna · error

JNA: error while handling callback exception, continuing

Error message

JNA: error while handling callback exception, continuing

What it means

When a Java callback throws, invoke_callback hands the throwable to handle_exception (the Callback.UncaughtExceptionHandler path). If that handler itself fails, JNA prints this message, has already cleared the exception, zeroes the native return buffer (for non-void returns), and continues the native call. It signals that both the callback and its exception handler failed.

Source

Thrown at native/callback.c:557

      }
    }
  }
  else {
    jobject result;
    jobjectArray params =
      (*env)->NewObjectArray(env, cif->nargs, classObject, NULL);
    unsigned int i;

    for (i=0;i < cif->nargs;i++) {
      jobject arg = new_object(env, cb->arg_jtypes[i], cbargs[i], JNI_FALSE, cb->encoding);
      (*env)->SetObjectArrayElement(env, params, i, arg);
    }
    result = (*env)->CallObjectMethod(env, self, cb->methodID, params);
    if ((*env)->ExceptionCheck(env)) {
      jthrowable throwable = (*env)->ExceptionOccurred(env);
      (*env)->ExceptionClear(env);
      if (!handle_exception(env, self, throwable)) {
        fprintf(stderr, "JNA: error while handling callback exception, continuing\n");
      }
      if (cif->rtype->type != FFI_TYPE_VOID)
        memset(resp, 0, cif->rtype->size);
    }
    else {
      extract_value(env, result, resp, cif->rtype->size, JNI_TRUE, cb->encoding);
    }
  }
}

static TLS_KEY_T tls_thread_data_key;
static thread_storage* get_thread_storage(JNIEnv* env) {
  thread_storage* tls = (thread_storage *)TLS_GET(tls_thread_data_key);
  if (tls == NULL) {
    tls = (thread_storage*)calloc(1, sizeof(thread_storage));
    if (!tls) {
      throwByName(env, EOutOfMemory, "JNA: Can't allocate thread storage");
    }

View on GitHub (pinned to d036ad9781)

Solutions

  1. Fix the exception inside your callback so no exception ever reaches handle_exception.
  2. Make the Callback's UncaughtExceptionHandler bulletproof: wrap its body in try-catch and never throw.
  3. Check stderr/stdout of the process for the original exception stack trace printed before this message.
  4. Ensure the callback class and its dependencies are loadable from the native callback thread's context classloader.

Example fix

// before
handler = ex -> log.info(ex.getMessage()); // NPE if message null -> handler throws
// after
handler = ex -> { try { log.warn("callback failed", ex); } catch (Throwable t) { /* swallow */ } };
Defensive patterns

Strategy: try-catch

Try / catch

// Install a handler that can never throw
callbackRef.setUncaughtExceptionHandler((cb, ex) -> {
  try { LOGGER.log(Level.SEVERE, "callback failed", ex); }
  catch (Throwable ignored) { }
});

Prevention

When it happens

Trigger: A Java Callback implementation throws, and the installed UncaughtExceptionHandler (or default handling via handle_exception) itself throws an exception or fails to run, right after CallObjectMethod sets a pending JNI exception.

Common situations: An uncaught exception handler that itself throws (e.g. logger misconfigured, NPE inside handler), exceptions thrown in callbacks invoked from native threads where class loading of the handler fails, or OOM inside exception handling.

Related errors


AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12). Data as JSON: /api/errors/7f9f200da39d0b74. Report an issue: GitHub.