slint-ui/slint · error

JNI error

Error message

JNI error: {e:#?}

What it means

print_jni_error is the Android backend's centralized JNI failure handler: any jni::errors::Error returned from a JNI call (class lookup failure, wrong argument type, Java exception pending, etc.) is funneled here and turned into a panic with a debug-formatted error. It is called from many backend entry points (event processing, input method, safe-area queries, helper construction), so seeing it means a Java-side interaction failed at runtime on Android, not that Slint logic itself is wrong.

Solutions

  1. Inspect the debug-formatted {e:#?}; common causes are JavaLangException, JNIEnv getenv failures, or detached threads
  2. Ensure every JNI call goes through a valid AndroidEnv/JNIEnv obtained for the calling thread, not cached across thread boundaries
  3. Check exception policy: with AttachmentExceptionPolicy::PreReThrowPostCatch the jni crate re-throws; clear pending exceptions with env.exception_clear() before further calls
  4. Verify the Java helper classes (SlintAndroidJavaHelper, DexFileClassLoader) loaded successfully at startup; a failed class load surfaces later as a JNI error
Defensive patterns

Strategy: try-catch

When it happens

Trigger: Thrown at internal/backends/android-activity/javahelper.rs:292 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of slint-ui/slint@bb937076de (2026-09-16). Data as JSON: /api/errors/6013662203b009f2. Report an issue: GitHub.

Appendix: source

Thrown at internal/backends/android-activity/javahelper.rs:292

    is_instance_of = {
        JClassLoader,
    }
}

bind_java_type! {
    DexFileClassLoader => "dalvik.system.DexClassLoader",
    constructors {
        fn new(dex_path: JString, optimized_directory: JString, library_search_path: JString, parent: JClassLoader),
    },
    is_instance_of = {
        JClassLoader,
    }
}

// See `AttachmentExceptionPolicy::PreReThrowPostCatch` in `jni` crate.
#[track_caller]
pub fn print_jni_error(_app: &AndroidApp, e: jni::errors::Error) -> ! {
    panic!("JNI error: {e:#?}")
}

#[allow(dead_code)]
pub struct JavaHelper(jni::refs::Global<SlintAndroidJavaHelper<'static>>, AndroidApp);

fn get_helper_class_loader(
    env: &mut Env,
    native_activity: &AndroidActivity<'_>,
) -> Result<&'static JClassLoader<'static>, jni::errors::Error> {
    static DEX_CLASS_LOADER: OnceLock<jni::refs::Global<JClassLoader<'static>>> = OnceLock::new();

    fn build_dex_class_loader<'local>(
        env: &mut Env<'local>,
        native_activity: &AndroidActivity<'_>,
    ) -> Result<JClassLoader<'local>, jni::errors::Error> {
        let native_activity = env.new_local_ref(native_activity)?;
        let app_context = AndroidContext::cast_local(env, native_activity)?;
        let context_class_loader = app_context.get_class_loader(env)?;

View on GitHub (pinned to bb937076de)