{"record":{"id":"4cf7c906e0bda7d1","repo":"tauri-apps/tauri","slug":"failed-to-run-on-webview-created-hook","errorCode":null,"errorMessage":"failed to run on_webview_created hook","messagePattern":"failed to run on_webview_created hook","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tauri/src/manager/webview.rs","lineNumber":677,"sourceCode":"    // let plugins know that a new webview has been added to the manager\n    let manager = webview.manager_owned();\n    let webview_ = webview.clone();\n    // run on main thread so the plugin store doesn't dead lock with the event loop handler in App\n    let _ = webview.run_on_main_thread(move || {\n      manager\n        .plugins\n        .lock()\n        .expect(\"poisoned plugin store\")\n        .webview_created(webview_);\n    });\n\n    #[cfg(all(target_os = \"ios\", feature = \"wry\"))]\n    {\n      webview\n        .with_webview(|w| {\n          unsafe { crate::ios::on_webview_created(w.inner() as _, w.view_controller() as _) };\n        })\n        .expect(\"failed to run on_webview_created hook\");\n    }\n\n    let event = crate::EventName::from_str(\"tauri://webview-created\");\n    let payload = Some(crate::webview::CreatedEvent {\n      label: webview.label().into(),\n    });\n\n    let _ = webview\n      .manager\n      .emit(event, EmitPayload::Serialize(&payload));\n\n    webview\n  }\n\n  pub fn eval_script_all<S: Into<String>>(&self, script: S) -> crate::Result<()> {\n    let script = script.into();\n    let webviews = self.webviews_lock().values().cloned().collect::<Vec<_>>();\n    webviews","sourceCodeStart":659,"sourceCodeEnd":695,"githubUrl":"https://github.com/tauri-apps/tauri/blob/460ec35447493200d64290dd7f015d5a91d0fd58/crates/tauri/src/manager/webview.rs#L659-L695","documentation":"During webview attachment on iOS (with the `wry` runtime), Tauri runs the `on_webview_created` hook through `with_webview`. If executing that platform hook fails, the builder panics with this message, aborting webview creation.","triggerScenarios":"Building a webview on iOS where `crate::ios::on_webview_created` cannot run against the native WKWebView/view-controller pointers — e.g. the webview was not created on the main thread or the native pointers are invalid.","commonSituations":"iOS apps creating webviews from background threads; custom iOS plugin code interfering with the WKWebView lifecycle; tauri/wry version mismatches on iOS.","solutions":["Ensure all webview creation happens on the iOS main thread (dispatch via `run_on_main_thread` or create from the main event loop).","Update tauri, tauri-build and wry to matching latest versions for your iOS target.","Check custom iOS plugins/hooks (`on_webview_created` consumers) for unsafe code that invalidates the webview or view controller.","Test with a minimal tauri iOS example to isolate whether your app code or the toolchain is at fault."],"exampleFix":"// before\napp.run(|app| { let _ = WebviewWindowBuilder::new(app, \"main\", Default::default()).build(); }); // off-main-thread on iOS\n// after\nlet handle = app.handle().clone();\nstd::thread::spawn(move || {\n  handle.run_on_main_thread(move || {\n    let _ = WebviewWindowBuilder::new(&handle, \"main\", Default::default()).build();\n  });\n});","handlingStrategy":"validation","validationCode":"// Guard: create webviews only on the main thread (iOS)\nif !std::thread::current().name().map_or(false, |n| n == \"main\") {\n  app.run_on_main_thread(|| create_window(app))?;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Create windows/webviews on the main thread on iOS","Keep tauri/wry iOS versions in lockstep","Test webview creation on a device early in iOS development"],"tags":["ios","webview","panic","mobile"],"backgroundTag":"module-init-failed","analyzedSha":"460ec35447493200d64290dd7f015d5a91d0fd58","analyzedAt":"2026-09-18T23:55:51.277Z","contentChangedAt":"2026-09-18T23:55:51.277Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}