java-native-access/jna · warning

JNA: could not detach thread after callback handling

Error message

JNA: could not detach thread after callback handling

What it means

After a native thread finished invoking a Java callback, JNA detaches that thread from the JVM if it attached it for the duration of the call. This message is printed to stderr when DetachCurrentThread returns non-zero, meaning the thread could not be detached and stays registered with the VM — a potential thread/JNI resource leak, though the callback itself already ran.

Source

Thrown at native/dispatch.c:2092

  }
  else {
    obj = (*env)->NewLocalRef(env, cb->object);
    if ((*env)->IsSameObject(env, obj, NULL)) {
      fprintf(stderr, "JNA: callback object has been garbage collected\n");
      if (cif->rtype->type != FFI_TYPE_VOID)
        memset(resp, 0, cif->rtype->size);
    }
    else {
      (*env)->CallVoidMethod(env, obj, MID_ffi_callback_invoke,
                             A2L(cif), A2L(resp), A2L(argp));
    }

    (*env)->PopLocalFrame(env, NULL);
  }

  if (!attached) {
    if ((*jvm)->DetachCurrentThread(jvm) != 0) {
      fprintf(stderr, "JNA: could not detach thread after callback handling\n");
    }
  }
}

////////////////////
// API Methods
////////////////////

/*
 * Class:     com_sun_jna_Native
 * Method:    invokePointer
 * Signature: (Lcom/sun/jna/Function;JI[Ljava/lang/Object;)J
 */
JNIEXPORT jlong JNICALL 
Java_com_sun_jna_Native_invokePointer (JNIEnv *env, jclass UNUSED(cls),
                                       jobject UNUSED(function), jlong fp,
                                       jint callconv, jobjectArray arr)
{

View on GitHub (pinned to d036ad9781)

Solutions

  1. Avoid foreign-thread callbacks: have native code post events to a queue drained by a Java thread, so no attach/detach happens per callback.
  2. Audit the callback for anything that leaves JNI references or monitors held on the thread (reentrancy, native mutexes acquired around the Java call).
  3. Ensure native threads are quiesced before JVM shutdown so detach is attempted on a live VM.
  4. Monitor thread counts to verify whether failed detaches are leaking, and restart or restructure if accumulation is observed.

Example fix

// before: native lib calls Java callback directly on C thread
native_set_event_handler(cb); // each event: attach + detach
// after: native fills a queue; Java thread drains it
native_start_queue_drain();
new Thread(() -> { while (running) handleEvent(native_pop_event()); }).start();
Defensive patterns

Strategy: fallback

Prevention

When it happens

Trigger: A callback fired on a foreign native thread; JNA attached it, invoked the Java method, popped the local frame, and then DetachCurrentThread failed (other JNI references/monitors still held on the thread, or JVM is shutting down).

Common situations: Native libraries (media codecs, device SDKs, event loops) that invoke callbacks from their own pooled threads; JVM teardown racing with in-flight callbacks; reentrant callbacks that leave state on the thread.

Related errors


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