{"record":{"id":"cc18d24f968fd7f1","repo":"java-native-access/jna","slug":"jna-error-handling-callback-exception-continuing","errorCode":null,"errorMessage":"JNA: error handling callback exception, continuing\n","messagePattern":"JNA: error handling callback exception, continuing\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"native/callback.c","lineNumber":481,"sourceCode":"          break;\n        }\n      }\n    }\n\n    if (cb->rflag == CVT_STRUCTURE_BYVAL) {\n      resp = alloca(sizeof(jobject));\n    }\n    else if (cb->cif.rtype->size > cif->rtype->size) {\n      resp = alloca(cb->cif.rtype->size);\n    }\n#define FPTR(ENV,OFFSET) (*(void **)((char *)(*(ENV)) + OFFSET))\n#define JNI_FN(X) ((void (*)(void))(X))\n    ffi_call(&cb->java_cif, JNI_FN(FPTR(env, cb->fptr_offset)), resp, args);\n    if ((*env)->ExceptionCheck(env)) {\n      jthrowable throwable = (*env)->ExceptionOccurred(env);\n      (*env)->ExceptionClear(env);\n      if (!handle_exception(env, self, throwable)) {\n        fprintf(stderr, \"JNA: error handling callback exception, continuing\\n\");\n      }\n      if (cif->rtype->type != FFI_TYPE_VOID) {\n        memset(oldresp, 0, cif->rtype->size);\n      }\n    }\n    else switch(cb->rflag) {\n    case CVT_INTEGER_TYPE:\n      if (cb->cif.rtype->size > sizeof(ffi_arg)) {\n        *(jlong *)oldresp = getIntegerTypeValue(env, *(void **)resp);\n      }\n      else {\n        *(ffi_arg *)oldresp = (ffi_arg)getIntegerTypeValue(env, *(void **)resp);\n      }\n      break;\n    case CVT_POINTER_TYPE:\n      *(void **)resp = getPointerTypeAddress(env, *(void **)resp);\n      break;\n    case CVT_NATIVE_MAPPED:","sourceCodeStart":463,"sourceCodeEnd":499,"githubUrl":"https://github.com/java-native-access/jna/blob/d036ad9781adad4b66693e8fa7098e4ac665e0a3/native/callback.c#L463-L499","documentation":"After ffi_call invokes the Java callback, if a Java exception is pending and the internal handle_exception path fails (returns 0), JNA prints this message to stderr, clears/continues, and zeroes the return buffer for non-void returns. It indicates an exception escaped the Java callback AND the installed exception handler (Callback.UncaughtExceptionHandler) could not process it.","triggerScenarios":"The Java callback method throws, and the registered UncaughtExceptionHandler itself throws, or none is installed and the default handling fails, when native code invokes the callback via ffi_call.","commonSituations":"Callbacks that throw unexpected runtime exceptions (NPE, etc.) while native code holds no Java exception expectations; misconfigured Callback.UncaughtExceptionHandler that itself errors.","solutions":["Wrap the callback body in try-catch and handle/log exceptions inside the callback itself.","Install a robust Callback.UncaughtExceptionHandler that cannot itself throw.","Note that the native return value is zeroed — design native callers to tolerate a zero/NULL result."],"exampleFix":"// before\npublic void invoke() { doWork(); } // exception escapes to native\n// after\npublic void invoke() {\n    try { doWork(); } catch (Throwable t) { log(t); }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Inside every callback body\npublic ReturnType invoke(...) {\n    try {\n        return realWork(...);\n    } catch (Throwable t) {\n        log.error(\"callback failed\", t);\n        return defaultValue; // zero/NULL-equivalent\n    }\n}","preventionTips":["Catch Throwable inside callback implementations; never let exceptions escape to native","Register a Callback.UncaughtExceptionHandler that cannot itself throw","Ensure native callers tolerate zeroed return values when a callback fails"],"tags":["jna","native","callback","uncaught-exception"],"backgroundTag":"uncaught-callback-exception","analyzedSha":"d036ad9781adad4b66693e8fa7098e4ac665e0a3","analyzedAt":"2026-09-12T06:50:59.239Z","contentChangedAt":"2026-09-12T06:50:59.239Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}