{"record":{"id":"fcc6ad8ee9160d81","repo":"DioxusLabs/dioxus","slug":"failed-to-get-asset-manager","errorCode":null,"errorMessage":"Failed to get asset manager","messagePattern":"Failed to get asset manager","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/asset-resolver/src/native.rs","lineNumber":278,"sourceCode":"            return std::fs::read(path).ok();\n        }\n    }\n\n    use std::ptr::NonNull;\n\n    let ctx = ndk_context::android_context();\n    let vm = unsafe { jni::JavaVM::from_raw(ctx.vm().cast()) }.unwrap();\n    let mut env = vm.attach_current_thread().unwrap();\n\n    // Query the Asset Manager\n    let asset_manager_ptr = env\n        .call_method(\n            unsafe { jni::objects::JObject::from_raw(ctx.context().cast()) },\n            \"getAssets\",\n            \"()Landroid/content/res/AssetManager;\",\n            &[],\n        )\n        .expect(\"Failed to get asset manager\")\n        .l()\n        .expect(\"Failed to get asset manager as object\");\n\n    unsafe {\n        let asset_manager =\n            ndk_sys::AAssetManager_fromJava(env.get_native_interface(), *asset_manager_ptr);\n\n        let asset_manager = ndk::asset::AssetManager::from_ptr(\n            NonNull::new(asset_manager).expect(\"Invalid asset manager\"),\n        );\n\n        let cstr = std::ffi::CString::new(normalized).unwrap();\n\n        let mut asset = asset_manager.open(&cstr)?;\n        Some(asset.buffer().unwrap().to_vec())\n    }\n}\n","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/DioxusLabs/dioxus/blob/393d190a801ccb441d41923e232289b4f8a5c669/packages/asset-resolver/src/native.rs#L260-L296","documentation":"Android-only panic in the asset resolver: it attaches the current thread to the JVM and calls the JNI getAssets method on the Activity context to obtain the Java AssetManager. The expect fires when that JNI call fails - most commonly because ndk-context was never initialized (code running outside a real Android app) or the JVM attach/context is unusable.","triggerScenarios":"Asset resolution reaching to_java_load_asset in a process without a valid Android context: plain cargo test/host unit tests touching asset loading, or custom JNI glue that never called ndk_context::initialize_android_context.","commonSituations":"Running desktop-style tests locally that hit asset!() code paths; debug builds where the asset is missing from the /data/local/tmp/dx/ cache so the JNI fallback is hit; custom entry points bypassing the dioxus/wry Android launcher.","solutions":["Run asset-touching code only inside a real Android app launched from an Activity (dx serve/build for Android)","Initialize ndk_context in custom JNI entry points before any asset code runs","Ensure debug assets are pushed so the /data/local/tmp/dx fast path serves them before JNI is reached","Gate host tests with #[cfg(not(target_os = \"android\"))] or mock the asset layer"],"exampleFix":"// before\n#[test]\nfn reads_config() { let bytes = load_asset(\"/assets/config.json\"); }\n\n// after\n#[cfg(target_os = \"android\")]\n#[test]\nfn reads_config() { let bytes = load_asset(\"/assets/config.json\"); }","handlingStrategy":"validation","validationCode":"// Only exercise Android asset paths inside a real Android app\n#[cfg(target_os = \"android\")]\nfn load_bytes(path: &str) -> Option<Vec<u8>> { /* touches JNI asset manager */ }\n\n#[cfg(not(target_os = \"android\"))]\nfn load_bytes(_path: &str) -> Option<Vec<u8>> { None }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never call Android asset resolution from host unit tests; cfg-gate those tests","Use the standard dioxus/wry Android launcher so ndk-context is initialized","In debug builds, ensure assets are pushed to the device cache so the JNI path is rarely hit"],"tags":["android","jni","assets","ndk","panic","runtime"],"backgroundTag":null,"analyzedSha":"393d190a801ccb441d41923e232289b4f8a5c669","analyzedAt":"2026-08-16T11:27:45.815Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}